github.com/consensys/gnark@v0.11.0/backend/plonk/bn254/setup.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 gnark DO NOT EDIT 16 17 package plonk 18 19 import ( 20 "fmt" 21 "github.com/consensys/gnark-crypto/ecc/bn254/fr" 22 "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" 23 "github.com/consensys/gnark-crypto/ecc/bn254/fr/iop" 24 "github.com/consensys/gnark-crypto/ecc/bn254/kzg" 25 "github.com/consensys/gnark/backend/plonk/internal" 26 "github.com/consensys/gnark/constraint" 27 cs "github.com/consensys/gnark/constraint/bn254" 28 ) 29 30 // VerifyingKey stores the data needed to verify a proof: 31 // * The commitment scheme 32 // * Commitments of ql prepended with as many ones as there are public inputs 33 // * Commitments of qr, qm, qo, qk prepended with as many zeroes as there are public inputs 34 // * Commitments to S1, S2, S3 35 type VerifyingKey struct { 36 // Size circuit 37 Size uint64 38 SizeInv fr.Element 39 Generator fr.Element 40 NbPublicVariables uint64 41 42 // Commitment scheme that is used for an instantiation of PLONK 43 Kzg kzg.VerifyingKey 44 45 // cosetShift generator of the coset on the small domain 46 CosetShift fr.Element 47 48 // S commitments to S1, S2, S3 49 S [3]kzg.Digest 50 51 // Commitments to ql, qr, qm, qo, qcp prepended with as many zeroes (ones for l) as there are public inputs. 52 // In particular Qk is not complete. 53 Ql, Qr, Qm, Qo, Qk kzg.Digest 54 Qcp []kzg.Digest 55 56 CommitmentConstraintIndexes []uint64 57 } 58 59 // Trace stores a plonk trace as columns 60 type Trace struct { 61 // Constants describing a plonk circuit. The first entries 62 // of LQk (whose index correspond to the public inputs) are set to 0, and are to be 63 // completed by the prover. At those indices i (so from 0 to nb_public_variables), LQl[i]=-1 64 // so the first nb_public_variables constraints look like this: 65 // -1*Wire[i] + 0* + 0 . It is zero when the constant coefficient is replaced by Wire[i]. 66 Ql, Qr, Qm, Qo, Qk *iop.Polynomial 67 Qcp []*iop.Polynomial 68 69 // Polynomials representing the splitted permutation. The full permutation's support is 3*N where N=nb wires. 70 // The set of interpolation is <g> of size N, so to represent the permutation S we let S acts on the 71 // set A=(<g>, u*<g>, u^{2}*<g>) of size 3*N, where u is outside <g> (its use is to shift the set <g>). 72 // We obtain a permutation of A, A'. We split A' in 3 (A'_{1}, A'_{2}, A'_{3}), and S1, S2, S3 are 73 // respectively the interpolation of A'_{1}, A'_{2}, A'_{3} on <g>. 74 S1, S2, S3 *iop.Polynomial 75 76 // S full permutation, i -> S[i] 77 S []int64 78 } 79 80 // ProvingKey stores the data needed to generate a proof 81 type ProvingKey struct { 82 Kzg, KzgLagrange kzg.ProvingKey 83 84 // Verifying Key is embedded into the proving key (needed by Prove) 85 Vk *VerifyingKey 86 } 87 88 func Setup(spr *cs.SparseR1CS, srs, srsLagrange kzg.SRS) (*ProvingKey, *VerifyingKey, error) { 89 90 var pk ProvingKey 91 var vk VerifyingKey 92 pk.Vk = &vk 93 vk.CommitmentConstraintIndexes = internal.IntSliceToUint64Slice(spr.CommitmentInfo.CommitmentIndexes()) 94 95 // step 0: set the fft domains 96 domain := initFFTDomain(spr) 97 if domain.Cardinality < 2 { 98 return nil, nil, fmt.Errorf("circuit has only %d constraints; unsupported by the current implementation", len(spr.Public)+spr.GetNbConstraints()) 99 } 100 101 // check the size of the kzg srs. 102 if len(srs.Pk.G1) < (int(domain.Cardinality) + 3) { // + 3 for the kzg.Open of blinded poly 103 return nil, nil, fmt.Errorf("kzg srs is too small: got %d, need %d", len(srs.Pk.G1), domain.Cardinality+3) 104 } 105 106 // same for the lagrange form 107 if len(srsLagrange.Pk.G1) != int(domain.Cardinality) { 108 return nil, nil, fmt.Errorf("kzg srs lagrange is too small: got %d, need %d", len(srsLagrange.Pk.G1), domain.Cardinality) 109 } 110 111 // step 1: set the verifying key 112 vk.CosetShift.Set(&domain.FrMultiplicativeGen) 113 vk.Size = domain.Cardinality 114 vk.SizeInv.SetUint64(vk.Size).Inverse(&vk.SizeInv) 115 vk.Generator.Set(&domain.Generator) 116 vk.NbPublicVariables = uint64(len(spr.Public)) 117 118 pk.Kzg.G1 = srs.Pk.G1[:int(vk.Size)+3] 119 pk.KzgLagrange.G1 = srsLagrange.Pk.G1 120 vk.Kzg = srs.Vk 121 122 // step 2: ql, qr, qm, qo, qk, qcp in Lagrange Basis 123 // step 3: build the permutation and build the polynomials S1, S2, S3 to encode the permutation. 124 // Note: at this stage, the permutation takes in account the placeholders 125 trace := NewTrace(spr, domain) 126 127 // step 4: commit to s1, s2, s3, ql, qr, qm, qo, and (the incomplete version of) qk. 128 // All the above polynomials are expressed in canonical basis afterwards. This is why 129 // we save lqk before, because the prover needs to complete it in Lagrange form, and 130 // then express it on the Lagrange coset basis. 131 if err := vk.commitTrace(trace, domain, pk.KzgLagrange); err != nil { 132 return nil, nil, err 133 } 134 135 return &pk, &vk, nil 136 } 137 138 // NbPublicWitness returns the expected public witness size (number of field elements) 139 func (vk *VerifyingKey) NbPublicWitness() int { 140 return int(vk.NbPublicVariables) 141 } 142 143 // VerifyingKey returns pk.Vk 144 func (pk *ProvingKey) VerifyingKey() interface{} { 145 return pk.Vk 146 } 147 148 // NewTrace returns a new Trace object from the constraint system. 149 // It fills the constant columns ql, qr, qm, qo, qk, and qcp with the 150 // coefficients of the constraints. 151 // Size is the size of the system that is next power of 2 (nb_constraints+nb_public_variables) 152 // The permutation is also computed and stored in the Trace. 153 func NewTrace(spr *cs.SparseR1CS, domain *fft.Domain) *Trace { 154 var trace Trace 155 156 size := int(domain.Cardinality) 157 commitmentInfo := spr.CommitmentInfo.(constraint.PlonkCommitments) 158 159 ql := make([]fr.Element, size) 160 qr := make([]fr.Element, size) 161 qm := make([]fr.Element, size) 162 qo := make([]fr.Element, size) 163 qk := make([]fr.Element, size) 164 qcp := make([][]fr.Element, len(commitmentInfo)) 165 166 for i := 0; i < len(spr.Public); i++ { // placeholders (-PUB_INPUT_i + qk_i = 0) TODO should return error if size is inconsistent 167 ql[i].SetOne().Neg(&ql[i]) 168 qr[i].SetZero() 169 qm[i].SetZero() 170 qo[i].SetZero() 171 qk[i].SetZero() // → to be completed by the prover 172 } 173 offset := len(spr.Public) 174 175 j := 0 176 it := spr.GetSparseR1CIterator() 177 for c := it.Next(); c != nil; c = it.Next() { 178 ql[offset+j].Set(&spr.Coefficients[c.QL]) 179 qr[offset+j].Set(&spr.Coefficients[c.QR]) 180 qm[offset+j].Set(&spr.Coefficients[c.QM]) 181 qo[offset+j].Set(&spr.Coefficients[c.QO]) 182 qk[offset+j].Set(&spr.Coefficients[c.QC]) 183 j++ 184 } 185 186 lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} 187 188 trace.Ql = iop.NewPolynomial(&ql, lagReg) 189 trace.Qr = iop.NewPolynomial(&qr, lagReg) 190 trace.Qm = iop.NewPolynomial(&qm, lagReg) 191 trace.Qo = iop.NewPolynomial(&qo, lagReg) 192 trace.Qk = iop.NewPolynomial(&qk, lagReg) 193 trace.Qcp = make([]*iop.Polynomial, len(qcp)) 194 195 for i := range commitmentInfo { 196 qcp[i] = make([]fr.Element, size) 197 for _, committed := range commitmentInfo[i].Committed { 198 qcp[i][offset+committed].SetOne() 199 } 200 trace.Qcp[i] = iop.NewPolynomial(&qcp[i], lagReg) 201 } 202 203 // build the permutation and build the polynomials S1, S2, S3 to encode the permutation. 204 // Note: at this stage, the permutation takes in account the placeholders 205 nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) 206 buildPermutation(spr, &trace, nbVariables) 207 s := computePermutationPolynomials(&trace, domain) 208 trace.S1 = s[0] 209 trace.S2 = s[1] 210 trace.S3 = s[2] 211 212 return &trace 213 } 214 215 // commitTrace commits to every polynomial in the trace, and put 216 // the commitments int the verifying key. 217 func (vk *VerifyingKey) commitTrace(trace *Trace, domain *fft.Domain, srsPk kzg.ProvingKey) error { 218 219 var err error 220 vk.Qcp = make([]kzg.Digest, len(trace.Qcp)) 221 for i := range trace.Qcp { 222 if vk.Qcp[i], err = kzg.Commit(trace.Qcp[i].Coefficients(), srsPk); err != nil { 223 return err 224 } 225 } 226 if vk.Ql, err = kzg.Commit(trace.Ql.Coefficients(), srsPk); err != nil { 227 return err 228 } 229 if vk.Qr, err = kzg.Commit(trace.Qr.Coefficients(), srsPk); err != nil { 230 return err 231 } 232 if vk.Qm, err = kzg.Commit(trace.Qm.Coefficients(), srsPk); err != nil { 233 return err 234 } 235 if vk.Qo, err = kzg.Commit(trace.Qo.Coefficients(), srsPk); err != nil { 236 return err 237 } 238 if vk.Qk, err = kzg.Commit(trace.Qk.Coefficients(), srsPk); err != nil { 239 return err 240 } 241 if vk.S[0], err = kzg.Commit(trace.S1.Coefficients(), srsPk); err != nil { 242 return err 243 } 244 if vk.S[1], err = kzg.Commit(trace.S2.Coefficients(), srsPk); err != nil { 245 return err 246 } 247 if vk.S[2], err = kzg.Commit(trace.S3.Coefficients(), srsPk); err != nil { 248 return err 249 } 250 return nil 251 } 252 253 func initFFTDomain(spr *cs.SparseR1CS) *fft.Domain { 254 nbConstraints := spr.GetNbConstraints() 255 sizeSystem := uint64(nbConstraints + len(spr.Public)) // len(spr.Public) is for the placeholder constraints 256 return fft.NewDomain(sizeSystem, fft.WithoutPrecompute()) 257 } 258 259 // buildPermutation builds the Permutation associated with a circuit. 260 // 261 // The permutation s is composed of cycles of maximum length such that 262 // 263 // s. (l∥r∥o) = (l∥r∥o) 264 // 265 // , where l∥r∥o is the concatenation of the indices of l, r, o in 266 // ql.l+qr.r+qm.l.r+qo.O+k = 0. 267 // 268 // The permutation is encoded as a slice s of size 3*size(l), where the 269 // i-th entry of l∥r∥o is sent to the s[i]-th entry, so it acts on a tab 270 // like this: for i in tab: tab[i] = tab[permutation[i]] 271 func buildPermutation(spr *cs.SparseR1CS, trace *Trace, nbVariables int) { 272 273 // nbVariables := spr.NbInternalVariables + len(spr.Public) + len(spr.Secret) 274 sizeSolution := len(trace.Ql.Coefficients()) 275 sizePermutation := 3 * sizeSolution 276 277 // init permutation 278 permutation := make([]int64, sizePermutation) 279 for i := 0; i < len(permutation); i++ { 280 permutation[i] = -1 281 } 282 283 // init LRO position -> variable_ID 284 lro := make([]int, sizePermutation) // position -> variable_ID 285 for i := 0; i < len(spr.Public); i++ { 286 lro[i] = i // IDs of LRO associated to placeholders (only L needs to be taken care of) 287 } 288 289 offset := len(spr.Public) 290 291 j := 0 292 it := spr.GetSparseR1CIterator() 293 for c := it.Next(); c != nil; c = it.Next() { 294 lro[offset+j] = int(c.XA) 295 lro[sizeSolution+offset+j] = int(c.XB) 296 lro[2*sizeSolution+offset+j] = int(c.XC) 297 298 j++ 299 } 300 301 // init cycle: 302 // map ID -> last position the ID was seen 303 cycle := make([]int64, nbVariables) 304 for i := 0; i < len(cycle); i++ { 305 cycle[i] = -1 306 } 307 308 for i := 0; i < len(lro); i++ { 309 if cycle[lro[i]] != -1 { 310 // if != -1, it means we already encountered this value 311 // so we need to set the corresponding permutation index. 312 permutation[i] = cycle[lro[i]] 313 } 314 cycle[lro[i]] = int64(i) 315 } 316 317 // complete the Permutation by filling the first IDs encountered 318 for i := 0; i < sizePermutation; i++ { 319 if permutation[i] == -1 { 320 permutation[i] = cycle[lro[i]] 321 } 322 } 323 324 trace.S = permutation 325 } 326 327 // computePermutationPolynomials computes the LDE (Lagrange basis) of the permutation. 328 // We let the permutation act on <g> || u<g> || u^{2}<g>, split the result in 3 parts, 329 // and interpolate each of the 3 parts on <g>. 330 func computePermutationPolynomials(trace *Trace, domain *fft.Domain) [3]*iop.Polynomial { 331 332 nbElmts := int(domain.Cardinality) 333 334 var res [3]*iop.Polynomial 335 336 // Lagrange form of ID 337 evaluationIDSmallDomain := getSupportPermutation(domain) 338 339 // Lagrange form of S1, S2, S3 340 s1Canonical := make([]fr.Element, nbElmts) 341 s2Canonical := make([]fr.Element, nbElmts) 342 s3Canonical := make([]fr.Element, nbElmts) 343 for i := 0; i < nbElmts; i++ { 344 s1Canonical[i].Set(&evaluationIDSmallDomain[trace.S[i]]) 345 s2Canonical[i].Set(&evaluationIDSmallDomain[trace.S[nbElmts+i]]) 346 s3Canonical[i].Set(&evaluationIDSmallDomain[trace.S[2*nbElmts+i]]) 347 } 348 349 lagReg := iop.Form{Basis: iop.Lagrange, Layout: iop.Regular} 350 res[0] = iop.NewPolynomial(&s1Canonical, lagReg) 351 res[1] = iop.NewPolynomial(&s2Canonical, lagReg) 352 res[2] = iop.NewPolynomial(&s3Canonical, lagReg) 353 354 return res 355 } 356 357 // getSupportPermutation returns the support on which the permutation acts, it is 358 // <g> || u<g> || u^{2}<g> 359 func getSupportPermutation(domain *fft.Domain) []fr.Element { 360 361 res := make([]fr.Element, 3*domain.Cardinality) 362 363 res[0].SetOne() 364 res[domain.Cardinality].Set(&domain.FrMultiplicativeGen) 365 res[2*domain.Cardinality].Square(&domain.FrMultiplicativeGen) 366 367 for i := uint64(1); i < domain.Cardinality; i++ { 368 res[i].Mul(&res[i-1], &domain.Generator) 369 res[domain.Cardinality+i].Mul(&res[domain.Cardinality+i-1], &domain.Generator) 370 res[2*domain.Cardinality+i].Mul(&res[2*domain.Cardinality+i-1], &domain.Generator) 371 } 372 373 return res 374 }