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