github.com/consensys/gnark@v0.11.0/internal/generator/backend/template/zkpschemes/plonkfri/plonk.setup.go.tmpl (about) 1 import ( 2 "crypto/sha256" 3 4 5 {{- template "import_fri" . }} 6 {{- template "import_fr" . }} 7 {{- template "import_fft" . }} 8 {{- template "import_backend_cs" . }} 9 ) 10 11 // ProvingKey stores the data needed to generate a proof: 12 // * the commitment scheme 13 // * ql, prepended with as many ones as they are public inputs 14 // * qr, qm, qo prepended with as many zeroes as there are public inputs. 15 // * qk, prepended with as many zeroes as public inputs, to be completed by the prover 16 // with the list of public inputs. 17 // * sigma_1, sigma_2, sigma_3 in both basis 18 // * the copy constraint permutation 19 type ProvingKey struct { 20 21 // Verifying Key is embedded into the proving key (needed by Prove) 22 Vk *VerifyingKey 23 24 // qr,ql,qm,qo and Qk incomplete (Ls=Lagrange basis big domain, L=Lagrange basis small domain, C=canonical basis) 25 EvaluationQlDomainBigBitReversed []fr.Element 26 EvaluationQrDomainBigBitReversed []fr.Element 27 EvaluationQmDomainBigBitReversed []fr.Element 28 EvaluationQoDomainBigBitReversed []fr.Element 29 LQkIncompleteDomainSmall []fr.Element 30 CQl, CQr, CQm, CQo, CQkIncomplete []fr.Element 31 32 // Domains used for the FFTs 33 // 0 -> "small" domain, used for individual polynomials 34 // 1 -> "big" domain, used for the computation of the quotient 35 Domain [2]fft.Domain 36 37 // s1, s2, s3 (L=Lagrange basis small domain, C=canonical basis, Ls=Lagrange Shifted big domain) 38 LId []fr.Element 39 EvaluationId1BigDomain, EvaluationId2BigDomain, EvaluationId3BigDomain []fr.Element 40 EvaluationS1BigDomain, EvaluationS2BigDomain, EvaluationS3BigDomain []fr.Element 41 42 // position -> permuted position (position in [0,3*sizeSystem-1]) 43 Permutation []int64 44 } 45 46 // VerifyingKey stores the data needed to verify a proof: 47 // * The commitment scheme 48 // * Commitments of ql prepended with as many ones as there are public inputs 49 // * Commitments of qr, qm, qo, qk prepended with as many zeroes as there are public inputs 50 // * Commitments to S1, S2, S3 51 type VerifyingKey struct { 52 53 // Size circuit, that is the closest power of 2 bounding above 54 // number of constraints+number of public inputs 55 Size uint64 56 SizeInv fr.Element 57 Generator fr.Element 58 NbPublicVariables uint64 59 60 // cosetShift generator of the coset on the small domain 61 CosetShift fr.Element 62 63 // S commitments to S1, S2, S3 64 SCanonical [3][]fr.Element 65 Spp [3]fri.ProofOfProximity 66 67 // Id commitments to Id1, Id2, Id3 68 // Id [3]Commitment 69 IdCanonical [3][]fr.Element 70 Idpp [3]fri.ProofOfProximity 71 72 // Commitments to ql, qr, qm, qo prepended with as many zeroes (ones for l) as there are public inputs. 73 // In particular Qk is not complete. 74 Qpp [5]fri.ProofOfProximity // Ql, Qr, Qm, Qo, Qk 75 76 // Iopp scheme (currently one for each size of polynomial) 77 Iopp fri.Iopp 78 79 // generator of the group on which the Iopp works. If i is the opening position, 80 // the polynomials will be opened at genOpening^{i}. 81 GenOpening fr.Element 82 } 83 84 // Setup sets proving and verifying keys 85 func Setup(spr *cs.SparseR1CS) (*ProvingKey, *VerifyingKey, error) { 86 87 var pk ProvingKey 88 var vk VerifyingKey 89 90 // The verifying key shares data with the proving key 91 pk.Vk = &vk 92 93 nbConstraints := spr.GetNbConstraints() 94 95 // fft domains 96 sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints 97 pk.Domain[0] = *fft.NewDomain(sizeSystem) 98 99 // h, the quotient polynomial is of degree 3(n+1)+2, so it's in a 3(n+2) dim vector space, 100 // the domain is the next power of 2 superior to 3(n+2). 4*domainNum is enough in all cases 101 // except when n<6. 102 if sizeSystem < 6 { 103 pk.Domain[1] = *fft.NewDomain(8 * sizeSystem) 104 } else { 105 pk.Domain[1] = *fft.NewDomain(4 * sizeSystem) 106 } 107 pk.Vk.CosetShift.Set(&pk.Domain[0].FrMultiplicativeGen) 108 109 vk.Size = pk.Domain[0].Cardinality 110 vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) 111 vk.Generator.Set(&pk.Domain[0].Generator) 112 vk.NbPublicVariables = uint64(len(spr.Public)) 113 114 // IOP schemess 115 // The +2 is to handle the blinding. 116 sizeIopp := pk.Domain[0].Cardinality + 2 117 vk.Iopp = fri.RADIX_2_FRI.New(sizeIopp, sha256.New()) 118 // only there to access the group used in FRI... 119 rho := uint64(fri.GetRho()) 120 // we multiply by 2 because the IOP is created with size pk.Domain[0].Cardinality + 2 (because 121 // of the blinding), so the domain will be rho*size_domain where size_domain is the next power 122 // of 2 after pk.Domain[0].Cardinality + 2, which is 2*rho*pk.Domain[0].Cardinality 123 tmpDomain := fft.NewDomain(2 * rho * pk.Domain[0].Cardinality) 124 vk.GenOpening.Set(&tmpDomain.Generator) 125 126 // public polynomials corresponding to constraints: [ placholders | constraints | assertions ] 127 pk.EvaluationQlDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) 128 pk.EvaluationQrDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) 129 pk.EvaluationQmDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) 130 pk.EvaluationQoDomainBigBitReversed = make([]fr.Element, pk.Domain[1].Cardinality) 131 pk.LQkIncompleteDomainSmall = make([]fr.Element, pk.Domain[0].Cardinality) 132 pk.CQkIncomplete = make([]fr.Element, pk.Domain[0].Cardinality) 133 134 for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error if size is inconsistent 135 pk.EvaluationQlDomainBigBitReversed[i].SetOne().Neg(&pk.EvaluationQlDomainBigBitReversed[i]) 136 pk.EvaluationQrDomainBigBitReversed[i].SetZero() 137 pk.EvaluationQmDomainBigBitReversed[i].SetZero() 138 pk.EvaluationQoDomainBigBitReversed[i].SetZero() 139 pk.LQkIncompleteDomainSmall[i].SetZero() // --> to be completed by the prover 140 pk.CQkIncomplete[i].Set(&pk.LQkIncompleteDomainSmall[i]) // --> to be completed by the prover 141 } 142 offset := len(spr.Public) 143 144 j := 0 145 it := spr.GetSparseR1CIterator() 146 for c := it.Next(); c!=nil; c = it.Next() { 147 pk.EvaluationQlDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QL]) 148 pk.EvaluationQrDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QR]) 149 pk.EvaluationQmDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QM]) 150 pk.EvaluationQoDomainBigBitReversed[offset+j].Set(&spr.Coefficients[c.QO]) 151 pk.LQkIncompleteDomainSmall[offset+j].Set(&spr.Coefficients[c.QC]) 152 pk.CQkIncomplete[offset+j].Set(&pk.LQkIncompleteDomainSmall[offset+j]) 153 154 j++ 155 } 156 157 158 pk.Domain[0].FFTInverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) 159 pk.Domain[0].FFTInverse(pk.EvaluationQrDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) 160 pk.Domain[0].FFTInverse(pk.EvaluationQmDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) 161 pk.Domain[0].FFTInverse(pk.EvaluationQoDomainBigBitReversed[:pk.Domain[0].Cardinality], fft.DIF) 162 pk.Domain[0].FFTInverse(pk.CQkIncomplete, fft.DIF) 163 fft.BitReverse(pk.EvaluationQlDomainBigBitReversed[:pk.Domain[0].Cardinality]) 164 fft.BitReverse(pk.EvaluationQrDomainBigBitReversed[:pk.Domain[0].Cardinality]) 165 fft.BitReverse(pk.EvaluationQmDomainBigBitReversed[:pk.Domain[0].Cardinality]) 166 fft.BitReverse(pk.EvaluationQoDomainBigBitReversed[:pk.Domain[0].Cardinality]) 167 fft.BitReverse(pk.CQkIncomplete) 168 169 // Commit to the polynomials to set up the verifying key 170 pk.CQl = make([]fr.Element, pk.Domain[0].Cardinality) 171 pk.CQr = make([]fr.Element, pk.Domain[0].Cardinality) 172 pk.CQm = make([]fr.Element, pk.Domain[0].Cardinality) 173 pk.CQo = make([]fr.Element, pk.Domain[0].Cardinality) 174 copy(pk.CQl, pk.EvaluationQlDomainBigBitReversed) 175 copy(pk.CQr, pk.EvaluationQrDomainBigBitReversed) 176 copy(pk.CQm, pk.EvaluationQmDomainBigBitReversed) 177 copy(pk.CQo, pk.EvaluationQoDomainBigBitReversed) 178 var err error 179 vk.Qpp[0], err = vk.Iopp.BuildProofOfProximity(pk.CQl) 180 if err != nil { 181 return &pk, &vk, err 182 } 183 vk.Qpp[1], err = vk.Iopp.BuildProofOfProximity(pk.CQr) 184 if err != nil { 185 return &pk, &vk, err 186 } 187 vk.Qpp[2], err = vk.Iopp.BuildProofOfProximity(pk.CQm) 188 if err != nil { 189 return &pk, &vk, err 190 } 191 vk.Qpp[3], err = vk.Iopp.BuildProofOfProximity(pk.CQo) 192 if err != nil { 193 return &pk, &vk, err 194 } 195 vk.Qpp[4], err = vk.Iopp.BuildProofOfProximity(pk.CQkIncomplete) 196 if err != nil { 197 return &pk, &vk, err 198 } 199 200 pk.Domain[1].FFT(pk.EvaluationQlDomainBigBitReversed, fft.DIF, fft.OnCoset()) 201 pk.Domain[1].FFT(pk.EvaluationQrDomainBigBitReversed, fft.DIF, fft.OnCoset()) 202 pk.Domain[1].FFT(pk.EvaluationQmDomainBigBitReversed, fft.DIF, fft.OnCoset()) 203 pk.Domain[1].FFT(pk.EvaluationQoDomainBigBitReversed, fft.DIF, fft.OnCoset()) 204 205 // build permutation. Note: at this stage, the permutation takes in account the placeholders 206 buildPermutation(spr, &pk) 207 208 // set s1, s2, s3 209 err = computePermutationPolynomials(&pk, &vk) 210 if err != nil { 211 return &pk, &vk, err 212 } 213 214 return &pk, &vk, nil 215 216 } 217 218 // buildPermutation builds the Permutation associated with a circuit. 219 // 220 // The permutation s is composed of cycles of maximum length such that 221 // 222 // s. (l||r||o) = (l||r||o) 223 // 224 //, where l||r||o is the concatenation of the indices of l, r, o in 225 // ql.l+qr.r+qm.l.r+qo.O+k = 0. 226 // 227 // The permutation is encoded as a slice s of size 3*size(l), where the 228 // i-th entry of l||r||o is sent to the s[i]-th entry, so it acts on a tab 229 // like this: for i in tab: tab[i] = tab[permutation[i]] 230 func buildPermutation(spr *cs.SparseR1CS, pk *ProvingKey) { 231 232 nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) 233 sizeSolution := int(pk.Domain[0].Cardinality) 234 235 // init permutation 236 pk.Permutation = make([]int64, 3*sizeSolution) 237 for i := 0; i < len(pk.Permutation); i++ { 238 pk.Permutation[i] = -1 239 } 240 241 // init LRO position -> variable_ID 242 lro := make([]int, 3*sizeSolution) // position -> variable_ID 243 for i := 0; i < len(spr.Public); i++ { 244 lro[i] = i // IDs of LRO associated to placeholders (only L needs to be taken care of) 245 } 246 247 offset := len(spr.Public) 248 249 j := 0 250 it := spr.GetSparseR1CIterator() 251 for c := it.Next(); c!=nil; c = it.Next() { 252 lro[offset+j] = int(c.XA) 253 lro[sizeSolution+offset+j] = int(c.XB) 254 lro[2*sizeSolution+offset+j] = int(c.XC) 255 j++ 256 } 257 258 // init cycle: 259 // map ID -> last position the ID was seen 260 cycle := make([]int64, nbVariables) 261 for i := 0; i < len(cycle); i++ { 262 cycle[i] = -1 263 } 264 265 for i := 0; i < len(lro); i++ { 266 if cycle[lro[i]] != -1 { 267 // if != -1, it means we already encountered this value 268 // so we need to set the corresponding permutation index. 269 pk.Permutation[i] = cycle[lro[i]] 270 } 271 cycle[lro[i]] = int64(i) 272 } 273 274 // complete the Permutation by filling the first IDs encountered 275 for i := 0; i < len(pk.Permutation); i++ { 276 if pk.Permutation[i] == -1 { 277 pk.Permutation[i] = cycle[lro[i]] 278 } 279 } 280 } 281 282 // computePermutationPolynomials computes the LDE (Lagrange basis) of the permutations 283 // s1, s2, s3. 284 // 285 // 0 1 .. n-1 | n n+1 .. 2*n-1 | 2n 2n+1 .. 3n-1 | 286 // | 287 // | Permutation 288 // s00 s01 .. s0n-1 s10 s11 .. s1n-1 s20 s21 .. s2n-1 v 289 // \---------------/ \--------------------/ \------------------------/ 290 // s1 (LDE) s2 (LDE) s3 (LDE) 291 func computePermutationPolynomials(pk *ProvingKey, vk *VerifyingKey) error { 292 293 nbElmt := int(pk.Domain[0].Cardinality) 294 295 // sID = [1,..,g^{n-1},s,..,s*g^{n-1},s^2,..,s^2*g^{n-1}] 296 pk.LId = getIDSmallDomain(&pk.Domain[0]) 297 298 // canonical form of S1, S2, S3 299 pk.EvaluationS1BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) 300 pk.EvaluationS2BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) 301 pk.EvaluationS3BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) 302 for i := 0; i < nbElmt; i++ { 303 pk.EvaluationS1BigDomain[i].Set(&pk.LId[pk.Permutation[i]]) 304 pk.EvaluationS2BigDomain[i].Set(&pk.LId[pk.Permutation[nbElmt+i]]) 305 pk.EvaluationS3BigDomain[i].Set(&pk.LId[pk.Permutation[2*nbElmt+i]]) 306 } 307 308 // Evaluations of Sid1, Sid2, Sid3 on cosets of Domain[1] 309 pk.EvaluationId1BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) 310 pk.EvaluationId2BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) 311 pk.EvaluationId3BigDomain = make([]fr.Element, pk.Domain[1].Cardinality) 312 copy(pk.EvaluationId1BigDomain, pk.LId[:nbElmt]) 313 copy(pk.EvaluationId2BigDomain, pk.LId[nbElmt:2*nbElmt]) 314 copy(pk.EvaluationId3BigDomain, pk.LId[2*nbElmt:]) 315 pk.Domain[0].FFTInverse(pk.EvaluationId1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) 316 pk.Domain[0].FFTInverse(pk.EvaluationId2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) 317 pk.Domain[0].FFTInverse(pk.EvaluationId3BigDomain[:pk.Domain[0].Cardinality], fft.DIF) 318 fft.BitReverse(pk.EvaluationId1BigDomain[:pk.Domain[0].Cardinality]) 319 fft.BitReverse(pk.EvaluationId2BigDomain[:pk.Domain[0].Cardinality]) 320 fft.BitReverse(pk.EvaluationId3BigDomain[:pk.Domain[0].Cardinality]) 321 vk.IdCanonical[0] = make([]fr.Element, pk.Domain[0].Cardinality) 322 vk.IdCanonical[1] = make([]fr.Element, pk.Domain[0].Cardinality) 323 vk.IdCanonical[2] = make([]fr.Element, pk.Domain[0].Cardinality) 324 copy(vk.IdCanonical[0], pk.EvaluationId1BigDomain) 325 copy(vk.IdCanonical[1], pk.EvaluationId2BigDomain) 326 copy(vk.IdCanonical[2], pk.EvaluationId3BigDomain) 327 328 var err error 329 vk.Idpp[0], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId1BigDomain) 330 if err != nil { 331 return err 332 } 333 vk.Idpp[1], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId2BigDomain) 334 if err != nil { 335 return err 336 } 337 vk.Idpp[2], err = vk.Iopp.BuildProofOfProximity(pk.EvaluationId3BigDomain) 338 if err != nil { 339 return err 340 } 341 pk.Domain[1].FFT(pk.EvaluationId1BigDomain, fft.DIF, fft.OnCoset()) 342 pk.Domain[1].FFT(pk.EvaluationId2BigDomain, fft.DIF, fft.OnCoset()) 343 pk.Domain[1].FFT(pk.EvaluationId3BigDomain, fft.DIF, fft.OnCoset()) 344 345 pk.Domain[0].FFTInverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality], fft.DIF) 346 pk.Domain[0].FFTInverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality], fft.DIF) 347 pk.Domain[0].FFTInverse(pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality], fft.DIF) 348 fft.BitReverse(pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality]) 349 fft.BitReverse(pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality]) 350 fft.BitReverse(pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality]) 351 352 // commit S1, S2, S3 353 vk.SCanonical[0] = make([]fr.Element, pk.Domain[0].Cardinality) 354 vk.SCanonical[1] = make([]fr.Element, pk.Domain[0].Cardinality) 355 vk.SCanonical[2] = make([]fr.Element, pk.Domain[0].Cardinality) 356 copy(vk.SCanonical[0], pk.EvaluationS1BigDomain[:pk.Domain[0].Cardinality]) 357 copy(vk.SCanonical[1], pk.EvaluationS2BigDomain[:pk.Domain[0].Cardinality]) 358 copy(vk.SCanonical[2], pk.EvaluationS3BigDomain[:pk.Domain[0].Cardinality]) 359 vk.Spp[0], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[0]) 360 if err != nil { 361 return err 362 } 363 vk.Spp[1], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[1]) 364 if err != nil { 365 return err 366 } 367 vk.Spp[2], err = vk.Iopp.BuildProofOfProximity(vk.SCanonical[2]) 368 if err != nil { 369 return err 370 } 371 pk.Domain[1].FFT(pk.EvaluationS1BigDomain, fft.DIF, fft.OnCoset()) 372 pk.Domain[1].FFT(pk.EvaluationS2BigDomain, fft.DIF, fft.OnCoset()) 373 pk.Domain[1].FFT(pk.EvaluationS3BigDomain, fft.DIF, fft.OnCoset()) 374 375 return nil 376 377 } 378 379 // getIDSmallDomain returns the Lagrange form of ID on the small domain 380 func getIDSmallDomain(domain *fft.Domain) []fr.Element { 381 382 res := make([]fr.Element, 3*domain.Cardinality) 383 384 res[0].SetOne() 385 res[domain.Cardinality].Set(&domain.FrMultiplicativeGen) 386 res[2*domain.Cardinality].Square(&domain.FrMultiplicativeGen) 387 388 for i := uint64(1); i < domain.Cardinality; i++ { 389 res[i].Mul(&res[i-1], &domain.Generator) 390 res[domain.Cardinality+i].Mul(&res[domain.Cardinality+i-1], &domain.Generator) 391 res[2*domain.Cardinality+i].Mul(&res[2*domain.Cardinality+i-1], &domain.Generator) 392 } 393 394 return res 395 } 396 397 // NbPublicWitness returns the expected public witness size (number of field elements) 398 func (vk *VerifyingKey) NbPublicWitness() int { 399 return int(vk.NbPublicVariables) 400 } 401 402 // VerifyingKey returns pk.Vk 403 func (pk *ProvingKey) VerifyingKey() interface{} { 404 return pk.Vk 405 }