github.com/consensys/gnark-crypto@v0.14.0/ecc/bls12-378/fr/permutation/permutation.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 permutation 18 19 import ( 20 "crypto/sha256" 21 "errors" 22 "math/big" 23 "math/bits" 24 25 "github.com/consensys/gnark-crypto/ecc/bls12-378" 26 "github.com/consensys/gnark-crypto/ecc/bls12-378/fr" 27 "github.com/consensys/gnark-crypto/ecc/bls12-378/fr/fft" 28 "github.com/consensys/gnark-crypto/ecc/bls12-378/kzg" 29 fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" 30 ) 31 32 var ( 33 ErrIncompatibleSize = errors.New("t1 and t2 should be of the same size") 34 ErrSize = errors.New("t1 and t2 should be of size a power of 2") 35 ErrPermutationProof = errors.New("permutation proof verification failed") 36 ErrGenerator = errors.New("wrong generator") 37 ) 38 39 // Proof proof that the commitments of t1 and t2 come from 40 // the same vector but permuted. 41 type Proof struct { 42 43 // size of the polynomials 44 size int 45 46 // generator of the fft domain, used for shifting the evaluation point 47 g fr.Element 48 49 // commitments of t1 & t2, the permuted vectors, and z, the accumulation 50 // polynomial 51 t1, t2, z kzg.Digest 52 53 // commitment to the quotient polynomial 54 q kzg.Digest 55 56 // opening proofs of t1, t2, z, q (in that order) 57 batchedProof kzg.BatchOpeningProof 58 59 // shifted opening proof of z 60 shiftedProof kzg.OpeningProof 61 } 62 63 // evaluateAccumulationPolynomialBitReversed returns the accumulation polynomial in Lagrange basis. 64 func evaluateAccumulationPolynomialBitReversed(lt1, lt2 []fr.Element, epsilon fr.Element) []fr.Element { 65 66 s := len(lt1) 67 z := make([]fr.Element, s) 68 d := make([]fr.Element, s) 69 z[0].SetOne() 70 d[0].SetOne() 71 nn := uint64(64 - bits.TrailingZeros64(uint64(s))) 72 var t fr.Element 73 for i := 0; i < s-1; i++ { 74 _i := int(bits.Reverse64(uint64(i)) >> nn) 75 _ii := int(bits.Reverse64(uint64((i+1)%s)) >> nn) 76 z[_ii].Mul(&z[_i], t.Sub(&epsilon, <1[i])) 77 d[i+1].Mul(&d[i], t.Sub(&epsilon, <2[i])) 78 } 79 d = fr.BatchInvert(d) 80 for i := 0; i < s-1; i++ { 81 _ii := int(bits.Reverse64(uint64((i+1)%s)) >> nn) 82 z[_ii].Mul(&z[_ii], &d[i+1]) 83 } 84 85 return z 86 } 87 88 // evaluateFirstPartNumReverse computes lt2*z(gx) - lt1*z 89 func evaluateFirstPartNumReverse(lt1, lt2, lz []fr.Element, epsilon fr.Element) []fr.Element { 90 91 s := len(lt1) 92 res := make([]fr.Element, s) 93 var a, b fr.Element 94 nn := uint64(64 - bits.TrailingZeros64(uint64(s))) 95 for i := 0; i < s; i++ { 96 _i := int(bits.Reverse64(uint64(i)) >> nn) 97 _ii := int(bits.Reverse64(uint64((i+1)%s)) >> nn) 98 a.Sub(&epsilon, <2[_i]) 99 a.Mul(&lz[_ii], &a) 100 b.Sub(&epsilon, <1[_i]) 101 b.Mul(&lz[_i], &b) 102 res[_i].Sub(&a, &b) 103 } 104 return res 105 } 106 107 // evaluateSecondPartNumReverse computes L0 * (z-1) 108 func evaluateSecondPartNumReverse(lz []fr.Element, d *fft.Domain) []fr.Element { 109 110 var tn, o, g fr.Element 111 o.SetOne() 112 tn.Exp(d.FrMultiplicativeGen, big.NewInt(int64(d.Cardinality))). 113 Sub(&tn, &o) 114 s := len(lz) 115 u := make([]fr.Element, s) 116 g.Set(&d.FrMultiplicativeGen) 117 for i := 0; i < s; i++ { 118 u[i].Sub(&g, &o) 119 g.Mul(&g, &d.Generator) 120 } 121 u = fr.BatchInvert(u) 122 res := make([]fr.Element, s) 123 nn := uint64(64 - bits.TrailingZeros64(uint64(s))) 124 for i := 0; i < s; i++ { 125 _i := int(bits.Reverse64(uint64(i)) >> nn) 126 res[_i].Sub(&lz[_i], &o). 127 Mul(&res[_i], &u[i]). 128 Mul(&res[_i], &tn) 129 } 130 return res 131 } 132 133 // Prove generates a proof that t1 and t2 are the same but permuted. 134 // The size of t1 and t2 should be the same and a power of 2. 135 func Prove(pk kzg.ProvingKey, t1, t2 []fr.Element) (Proof, error) { 136 137 // res 138 var proof Proof 139 var err error 140 141 // size checking 142 if len(t1) != len(t2) { 143 return proof, ErrIncompatibleSize 144 } 145 146 // create the domains 147 d := fft.NewDomain(uint64(len(t1))) 148 if d.Cardinality != uint64(len(t1)) { 149 return proof, ErrSize 150 } 151 s := int(d.Cardinality) 152 proof.size = s 153 proof.g.Set(&d.Generator) 154 155 // hash function for Fiat Shamir 156 hFunc := sha256.New() 157 158 // transcript to derive the challenge 159 fs := fiatshamir.NewTranscript(hFunc, "epsilon", "omega", "eta") 160 161 // commit t1, t2 162 ct1 := make([]fr.Element, s) 163 ct2 := make([]fr.Element, s) 164 copy(ct1, t1) 165 copy(ct2, t2) 166 d.FFTInverse(ct1, fft.DIF) 167 d.FFTInverse(ct2, fft.DIF) 168 fft.BitReverse(ct1) 169 fft.BitReverse(ct2) 170 proof.t1, err = kzg.Commit(ct1, pk) 171 if err != nil { 172 return proof, err 173 } 174 proof.t2, err = kzg.Commit(ct2, pk) 175 if err != nil { 176 return proof, err 177 } 178 179 // derive challenge for z 180 epsilon, err := deriveRandomness(fs, "epsilon", &proof.t1, &proof.t2) 181 if err != nil { 182 return proof, err 183 } 184 185 // compute Z and commit it 186 cz := evaluateAccumulationPolynomialBitReversed(t1, t2, epsilon) 187 d.FFTInverse(cz, fft.DIT) 188 proof.z, err = kzg.Commit(cz, pk) 189 if err != nil { 190 return proof, err 191 } 192 lz := make([]fr.Element, s) 193 copy(lz, cz) 194 d.FFT(lz, fft.DIF, fft.OnCoset()) 195 196 // compute the first part of the numerator 197 lt1 := make([]fr.Element, s) 198 lt2 := make([]fr.Element, s) 199 copy(lt1, ct1) 200 copy(lt2, ct2) 201 d.FFT(lt1, fft.DIF, fft.OnCoset()) 202 d.FFT(lt2, fft.DIF, fft.OnCoset()) 203 lsNumFirstPart := evaluateFirstPartNumReverse(lt1, lt2, lz, epsilon) 204 205 // compute second part of the numerator 206 lsNum := evaluateSecondPartNumReverse(lz, d) 207 208 // derive challenge used for the folding 209 omega, err := deriveRandomness(fs, "omega", &proof.z) 210 if err != nil { 211 return proof, err 212 } 213 214 // fold the numerator and divide it by x^n-1 215 var t, one fr.Element 216 one.SetOne() 217 t.Exp(d.FrMultiplicativeGen, big.NewInt(int64(d.Cardinality))).Sub(&t, &one).Inverse(&t) 218 for i := 0; i < s; i++ { 219 lsNum[i].Mul(&omega, &lsNum[i]). 220 Add(&lsNum[i], &lsNumFirstPart[i]). 221 Mul(&lsNum[i], &t) 222 } 223 224 // get the quotient and commit it 225 d.FFTInverse(lsNum, fft.DIT, fft.OnCoset()) 226 proof.q, err = kzg.Commit(lsNum, pk) 227 if err != nil { 228 return proof, err 229 } 230 231 // derive the evaluation challenge 232 eta, err := deriveRandomness(fs, "eta", &proof.q) 233 if err != nil { 234 return proof, err 235 } 236 237 // compute the opening proofs 238 proof.batchedProof, err = kzg.BatchOpenSinglePoint( 239 [][]fr.Element{ 240 ct1, 241 ct2, 242 cz, 243 lsNum, 244 }, 245 []kzg.Digest{ 246 proof.t1, 247 proof.t2, 248 proof.z, 249 proof.q, 250 }, 251 eta, 252 hFunc, 253 pk, 254 ) 255 if err != nil { 256 return proof, err 257 } 258 259 var shiftedEta fr.Element 260 shiftedEta.Mul(&eta, &d.Generator) 261 proof.shiftedProof, err = kzg.Open( 262 cz, 263 shiftedEta, 264 pk, 265 ) 266 if err != nil { 267 return proof, err 268 } 269 270 // done 271 return proof, nil 272 273 } 274 275 // Verify verifies a permutation proof. 276 func Verify(vk kzg.VerifyingKey, proof Proof) error { 277 278 // hash function that is used for Fiat Shamir 279 hFunc := sha256.New() 280 281 // transcript to derive the challenge 282 fs := fiatshamir.NewTranscript(hFunc, "epsilon", "omega", "eta") 283 284 // derive the challenges 285 epsilon, err := deriveRandomness(fs, "epsilon", &proof.t1, &proof.t2) 286 if err != nil { 287 return err 288 } 289 290 omega, err := deriveRandomness(fs, "omega", &proof.z) 291 if err != nil { 292 return err 293 } 294 295 eta, err := deriveRandomness(fs, "eta", &proof.q) 296 if err != nil { 297 return err 298 } 299 300 // check the relation 301 bs := big.NewInt(int64(proof.size)) 302 var l0, a, b, one, rhs, lhs fr.Element 303 one.SetOne() 304 rhs.Exp(eta, bs). 305 Sub(&rhs, &one) 306 a.Sub(&eta, &one) 307 l0.Div(&rhs, &a) 308 rhs.Mul(&rhs, &proof.batchedProof.ClaimedValues[3]) 309 a.Sub(&epsilon, &proof.batchedProof.ClaimedValues[1]). 310 Mul(&a, &proof.shiftedProof.ClaimedValue) 311 b.Sub(&epsilon, &proof.batchedProof.ClaimedValues[0]). 312 Mul(&b, &proof.batchedProof.ClaimedValues[2]) 313 lhs.Sub(&a, &b) 314 a.Sub(&proof.batchedProof.ClaimedValues[2], &one). 315 Mul(&a, &l0). 316 Mul(&a, &omega) 317 lhs.Add(&a, &lhs) 318 if !lhs.Equal(&rhs) { 319 return ErrPermutationProof 320 } 321 322 // check the opening proofs 323 err = kzg.BatchVerifySinglePoint( 324 []kzg.Digest{ 325 proof.t1, 326 proof.t2, 327 proof.z, 328 proof.q, 329 }, 330 &proof.batchedProof, 331 eta, 332 hFunc, 333 vk, 334 ) 335 if err != nil { 336 return err 337 } 338 339 var shiftedEta fr.Element 340 shiftedEta.Mul(&eta, &proof.g) 341 err = kzg.Verify(&proof.z, &proof.shiftedProof, shiftedEta, vk) 342 if err != nil { 343 return err 344 } 345 346 // check the generator is correct 347 var checkOrder fr.Element 348 checkOrder.Exp(proof.g, big.NewInt(int64(proof.size/2))) 349 if checkOrder.Equal(&one) { 350 return ErrGenerator 351 } 352 checkOrder.Square(&checkOrder) 353 if !checkOrder.Equal(&one) { 354 return ErrGenerator 355 } 356 357 return nil 358 } 359 360 // TODO put that in fiat-shamir package 361 func deriveRandomness(fs *fiatshamir.Transcript, challenge string, points ...*bls12378.G1Affine) (fr.Element, error) { 362 363 var buf [bls12378.SizeOfG1AffineUncompressed]byte 364 var r fr.Element 365 366 for _, p := range points { 367 buf = p.RawBytes() 368 if err := fs.Bind(challenge, buf[:]); err != nil { 369 return r, err 370 } 371 } 372 373 b, err := fs.ComputeChallenge(challenge) 374 if err != nil { 375 return r, err 376 } 377 r.SetBytes(b) 378 return r, nil 379 }