github.com/consensys/gnark-crypto@v0.14.0/ecc/bls12-377/fr/fri/fri_test.go (about)

     1  // Copyright 2020 Consensys Software Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Code generated by consensys/gnark-crypto DO NOT EDIT
    16  
    17  package fri
    18  
    19  import (
    20  	"crypto/sha256"
    21  	"fmt"
    22  	"math/big"
    23  	"testing"
    24  
    25  	"github.com/consensys/gnark-crypto/ecc/bls12-377/fr"
    26  	"github.com/leanovate/gopter"
    27  	"github.com/leanovate/gopter/gen"
    28  	"github.com/leanovate/gopter/prop"
    29  )
    30  
    31  // logFiber returns u, v such that {g^u, g^v} = f⁻¹((g²)^{_p})
    32  func logFiber(_p, _n int) (_u, _v big.Int) {
    33  	if _p%2 == 0 {
    34  		_u.SetInt64(int64(_p / 2))
    35  		_v.SetInt64(int64(_p/2 + _n/2))
    36  	} else {
    37  		l := (_n - 1 - _p) / 2
    38  		_u.SetInt64(int64(_n - 1 - l))
    39  		_v.SetInt64(int64(_n - 1 - l - _n/2))
    40  	}
    41  	return
    42  }
    43  
    44  func randomPolynomial(size uint64, seed int32) []fr.Element {
    45  	p := make([]fr.Element, size)
    46  	p[0].SetUint64(uint64(seed))
    47  	for i := 1; i < len(p); i++ {
    48  		p[i].Square(&p[i-1])
    49  	}
    50  	return p
    51  }
    52  
    53  // convertOrderCanonical convert the index i, an entry in a
    54  // sorted polynomial, to the corresponding entry in canonical
    55  // representation. n is the size of the polynomial.
    56  func convertSortedCanonical(i, n int) int {
    57  	if i%2 == 0 {
    58  		return i / 2
    59  	} else {
    60  		l := (n - 1 - i) / 2
    61  		return n - 1 - l
    62  	}
    63  }
    64  
    65  func TestFRI(t *testing.T) {
    66  
    67  	parameters := gopter.DefaultTestParameters()
    68  	parameters.MinSuccessfulTests = 10
    69  
    70  	properties := gopter.NewProperties(parameters)
    71  
    72  	size := 4096
    73  
    74  	properties.Property("verifying wrong opening should fail", prop.ForAll(
    75  
    76  		func(m int32) bool {
    77  
    78  			_s := RADIX_2_FRI.New(uint64(size), sha256.New())
    79  			s := _s.(radixTwoFri)
    80  
    81  			p := randomPolynomial(uint64(size), m)
    82  
    83  			pos := int64(m % 4096)
    84  			pp, _ := s.BuildProofOfProximity(p)
    85  
    86  			openingProof, err := s.Open(p, uint64(pos))
    87  			if err != nil {
    88  				t.Fatal(err)
    89  			}
    90  
    91  			// check the Merkle path
    92  			tamperedPosition := pos + 1
    93  			err = s.VerifyOpening(uint64(tamperedPosition), openingProof, pp)
    94  
    95  			return err != nil
    96  
    97  		},
    98  		gen.Int32Range(1, int32(rho*size)),
    99  	))
   100  
   101  	properties.Property("verifying correct opening should succeed", prop.ForAll(
   102  
   103  		func(m int32) bool {
   104  
   105  			_s := RADIX_2_FRI.New(uint64(size), sha256.New())
   106  			s := _s.(radixTwoFri)
   107  
   108  			p := randomPolynomial(uint64(size), m)
   109  
   110  			pos := uint64(m % int32(size))
   111  			pp, _ := s.BuildProofOfProximity(p)
   112  
   113  			openingProof, err := s.Open(p, uint64(pos))
   114  			if err != nil {
   115  				t.Fatal(err)
   116  			}
   117  
   118  			// check the Merkle path
   119  			err = s.VerifyOpening(uint64(pos), openingProof, pp)
   120  
   121  			return err == nil
   122  
   123  		},
   124  		gen.Int32Range(0, int32(rho*size)),
   125  	))
   126  
   127  	properties.Property("The claimed value of a polynomial should match P(x)", prop.ForAll(
   128  		func(m int32) bool {
   129  
   130  			_s := RADIX_2_FRI.New(uint64(size), sha256.New())
   131  			s := _s.(radixTwoFri)
   132  
   133  			p := randomPolynomial(uint64(size), m)
   134  
   135  			// check the opening value
   136  			var g fr.Element
   137  			pos := int64(m % 4096)
   138  			g.Set(&s.domain.Generator)
   139  			g.Exp(g, big.NewInt(pos))
   140  
   141  			var val fr.Element
   142  			for i := len(p) - 1; i >= 0; i-- {
   143  				val.Mul(&val, &g)
   144  				val.Add(&p[i], &val)
   145  			}
   146  
   147  			openingProof, err := s.Open(p, uint64(pos))
   148  			if err != nil {
   149  				t.Fatal(err)
   150  			}
   151  
   152  			return openingProof.ClaimedValue.Equal(&val)
   153  
   154  		},
   155  		gen.Int32Range(0, int32(rho*size)),
   156  	))
   157  
   158  	properties.Property("Derive queries position: points should belong the correct fiber", prop.ForAll(
   159  
   160  		func(m int32) bool {
   161  
   162  			_s := RADIX_2_FRI.New(uint64(size), sha256.New())
   163  			s := _s.(radixTwoFri)
   164  
   165  			var g fr.Element
   166  
   167  			_m := int(m) % size
   168  			pos := s.deriveQueriesPositions(_m, int(s.domain.Cardinality))
   169  			g.Set(&s.domain.Generator)
   170  			n := int(s.domain.Cardinality)
   171  
   172  			for i := 0; i < len(pos)-1; i++ {
   173  
   174  				u, v := logFiber(pos[i], n)
   175  
   176  				var g1, g2, g3 fr.Element
   177  				g1.Exp(g, &u).Square(&g1)
   178  				g2.Exp(g, &v).Square(&g2)
   179  				nextPos := convertSortedCanonical(pos[i+1], n/2)
   180  				g3.Square(&g).Exp(g3, big.NewInt(int64(nextPos)))
   181  
   182  				if !g1.Equal(&g2) || !g1.Equal(&g3) {
   183  					return false
   184  				}
   185  				g.Square(&g)
   186  				n = n >> 1
   187  			}
   188  			return true
   189  		},
   190  		gen.Int32Range(0, int32(rho*size)),
   191  	))
   192  
   193  	properties.Property("verifying a correctly formed proof should succeed", prop.ForAll(
   194  
   195  		func(s int32) bool {
   196  
   197  			p := randomPolynomial(uint64(size), s)
   198  
   199  			iop := RADIX_2_FRI.New(uint64(size), sha256.New())
   200  			proof, err := iop.BuildProofOfProximity(p)
   201  			if err != nil {
   202  				t.Fatal(err)
   203  			}
   204  
   205  			err = iop.VerifyProofOfProximity(proof)
   206  			return err == nil
   207  		},
   208  		gen.Int32Range(0, int32(rho*size)),
   209  	))
   210  
   211  	properties.TestingRun(t, gopter.ConsoleReporter(false))
   212  
   213  }
   214  
   215  // Benchmarks
   216  
   217  func BenchmarkProximityVerification(b *testing.B) {
   218  
   219  	baseSize := 16
   220  
   221  	for i := 0; i < 10; i++ {
   222  
   223  		size := baseSize << i
   224  		p := make([]fr.Element, size)
   225  		for k := 0; k < size; k++ {
   226  			p[k].SetRandom()
   227  		}
   228  
   229  		iop := RADIX_2_FRI.New(uint64(size), sha256.New())
   230  		proof, _ := iop.BuildProofOfProximity(p)
   231  
   232  		b.Run(fmt.Sprintf("Polynomial size %d", size), func(b *testing.B) {
   233  			b.ResetTimer()
   234  			for l := 0; l < b.N; l++ {
   235  				iop.VerifyProofOfProximity(proof)
   236  			}
   237  		})
   238  
   239  	}
   240  }