github.com/consensys/gnark-crypto@v0.14.0/ecc/bw6-756/fr/pedersen/pedersen.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 pedersen 18 19 import ( 20 "crypto/rand" 21 "errors" 22 "github.com/consensys/gnark-crypto/ecc" 23 curve "github.com/consensys/gnark-crypto/ecc/bw6-756" 24 "github.com/consensys/gnark-crypto/ecc/bw6-756/fr" 25 "io" 26 "math/big" 27 ) 28 29 // ProvingKey for committing and proofs of knowledge 30 type ProvingKey struct { 31 Basis []curve.G1Affine 32 BasisExpSigma []curve.G1Affine // basisExpSigma[i] = Basis[i]^{σ} 33 } 34 35 type VerifyingKey struct { 36 G curve.G2Affine 37 GSigma curve.G2Affine // GRootSigmaNeg = G^{-σ} 38 } 39 40 func randomFrSizedBytes() ([]byte, error) { 41 res := make([]byte, fr.Bytes) 42 _, err := rand.Read(res) 43 return res, err 44 } 45 46 type setupConfig struct { 47 g2Gen *curve.G2Affine 48 } 49 50 // SetupOption allows to customize Pedersen vector commitment setup. 51 type SetupOption func(cfg *setupConfig) 52 53 // WithG2Point allows to set the G2 generator for the Pedersen vector commitment 54 // setup. If this is not set, we sample a random G2 point. 55 func WithG2Point(g2 curve.G2Affine) SetupOption { 56 return func(cfg *setupConfig) { 57 cfg.g2Gen = &g2 58 } 59 } 60 61 // Setup generates the proving keys for Pedersen commitments over the given 62 // bases allowing for batch proving. The common verifying key can be used to 63 // verify the batched proof of knowledge. 64 // 65 // By default the G2 generator is sampled randomly. This can be overridden by 66 // providing a custom G2 generator using [WithG2Point] option. 67 // 68 // The input bases do not have to be of the same length for individual 69 // committing and proving. The elements in bases[i] should be linearly 70 // independent of each other. Otherwise the prover may be able to construct 71 // multiple valid openings for a commitment. 72 // 73 // NB! This is a trusted setup process. The randomness during the setup must be discarded. 74 // Failing to do so allows to create proofs without knowing the committed values. 75 func Setup(bases [][]curve.G1Affine, options ...SetupOption) (pk []ProvingKey, vk VerifyingKey, err error) { 76 var cfg setupConfig 77 for _, o := range options { 78 o(&cfg) 79 } 80 if cfg.g2Gen == nil { 81 if vk.G, err = curve.RandomOnG2(); err != nil { 82 return 83 } 84 } else { 85 vk.G = *cfg.g2Gen 86 } 87 88 var modMinusOne big.Int 89 modMinusOne.Sub(fr.Modulus(), big.NewInt(1)) 90 var sigma *big.Int 91 if sigma, err = rand.Int(rand.Reader, &modMinusOne); err != nil { 92 return 93 } 94 sigma.Add(sigma, big.NewInt(1)) 95 96 sigmaNeg := new(big.Int).Neg(sigma) 97 vk.GSigma.ScalarMultiplication(&vk.G, sigmaNeg) 98 99 pk = make([]ProvingKey, len(bases)) 100 for i := range bases { 101 pk[i].BasisExpSigma = make([]curve.G1Affine, len(bases[i])) 102 for j := range bases[i] { 103 pk[i].BasisExpSigma[j].ScalarMultiplication(&bases[i][j], sigma) 104 } 105 pk[i].Basis = bases[i] 106 } 107 return 108 } 109 110 // ProveKnowledge generates a proof of knowledge of a commitment to the given 111 // values over proving key's basis. 112 func (pk *ProvingKey) ProveKnowledge(values []fr.Element) (pok curve.G1Affine, err error) { 113 if len(values) != len(pk.Basis) { 114 err = errors.New("must have as many values as basis elements") 115 return 116 } 117 118 // TODO @gbotrel this will spawn more than one task, see 119 // https://github.com/ConsenSys/gnark-crypto/issues/269 120 config := ecc.MultiExpConfig{ 121 NbTasks: 1, // TODO Experiment 122 } 123 124 _, err = pok.MultiExp(pk.BasisExpSigma, values, config) 125 return 126 } 127 128 // Commit computes a commitment to the values over proving key's basis 129 func (pk *ProvingKey) Commit(values []fr.Element) (commitment curve.G1Affine, err error) { 130 131 if len(values) != len(pk.Basis) { 132 err = errors.New("must have as many values as basis elements") 133 return 134 } 135 136 // TODO @gbotrel this will spawn more than one task, see 137 // https://github.com/ConsenSys/gnark-crypto/issues/269 138 config := ecc.MultiExpConfig{ 139 NbTasks: 1, 140 } 141 _, err = commitment.MultiExp(pk.Basis, values, config) 142 143 return 144 } 145 146 // BatchProve computes a single proof of knowledge for multiple commitments. The 147 // single PoK can be verified with a single call to [VerifyingKey.Verify] with 148 // folded commitments. The commitments can be folded into one using [curve.G1Affine.Fold]. 149 // 150 // The argument combinationCoeff is used as a linear combination coefficient to 151 // fold separate proofs into one. It must be the same for batch proving and when 152 // folding commitments. This means that in an interactive setting, it must be 153 // randomly generated by the verifier and sent to the prover. Otherwise, it must 154 // be generated via Fiat-Shamir. 155 func BatchProve(pk []ProvingKey, values [][]fr.Element, combinationCoeff fr.Element) (pok curve.G1Affine, err error) { 156 if len(pk) != len(values) { 157 err = errors.New("must have as many value vectors as bases") 158 return 159 } 160 161 if len(pk) == 1 { // no need to fold 162 pok, err = pk[0].ProveKnowledge(values[0]) 163 return 164 } else if len(pk) == 0 { // nothing to do at all 165 return 166 } 167 168 offset := 0 169 for i := range pk { 170 if len(values[i]) != len(pk[i].Basis) { 171 err = errors.New("must have as many values as basis elements") 172 return 173 } 174 offset += len(values[i]) 175 } 176 177 // prepare one amalgamated MSM 178 scaledValues := make([]fr.Element, offset) 179 basis := make([]curve.G1Affine, offset) 180 181 copy(basis, pk[0].BasisExpSigma) // #nosec G602 false positive 182 copy(scaledValues, values[0]) // #nosec G602 false positive 183 184 offset = len(values[0]) // #nosec G602 false positive 185 rI := combinationCoeff 186 for i := 1; i < len(pk); i++ { 187 copy(basis[offset:], pk[i].BasisExpSigma) 188 for j := range pk[i].Basis { 189 scaledValues[offset].Mul(&values[i][j], &rI) 190 offset++ 191 } 192 if i+1 < len(pk) { 193 rI.Mul(&rI, &combinationCoeff) 194 } 195 } 196 197 // TODO @gbotrel this will spawn more than one task, see 198 // https://github.com/ConsenSys/gnark-crypto/issues/269 199 config := ecc.MultiExpConfig{ 200 NbTasks: 1, 201 } 202 203 _, err = pok.MultiExp(basis, scaledValues, config) 204 return 205 } 206 207 // Verify checks if the proof of knowledge is valid for a given commitment. 208 func (vk *VerifyingKey) Verify(commitment curve.G1Affine, knowledgeProof curve.G1Affine) error { 209 210 if !commitment.IsInSubGroup() || !knowledgeProof.IsInSubGroup() { 211 return errors.New("subgroup check failed") 212 } 213 214 if isOne, err := curve.PairingCheck([]curve.G1Affine{commitment, knowledgeProof}, []curve.G2Affine{vk.GSigma, vk.G}); err != nil { 215 return err 216 } else if !isOne { 217 return errors.New("proof rejected") 218 } 219 return nil 220 } 221 222 // BatchVerifyMultiVk verifies multiple separate proofs of knowledge using n+1 223 // pairings instead of 2n pairings. 224 // 225 // The verifying keys may be from different setup ceremonies, but the G2 point 226 // must be the same. This can be enforced using [WithG2Point] option during 227 // setup. 228 // 229 // The argument combinationCoeff is used as a linear combination coefficient to 230 // fold separate proofs into one. This means that in an interactive setting, it 231 // must be randomly generated by the verifier and sent to the prover. Otherwise, 232 // it must be generated via Fiat-Shamir. 233 // 234 // The prover can fold the proofs using [curve.G1Affine.Fold] itself using the 235 // random challenge, providing the verifier only the folded proof. In this case 236 // the argument pok should contain only the single folded proof. 237 func BatchVerifyMultiVk(vk []VerifyingKey, commitments []curve.G1Affine, pok []curve.G1Affine, combinationCoeff fr.Element) error { 238 if len(commitments) != len(vk) { 239 return errors.New("commitments length mismatch") 240 } 241 // we use folded POK if provided 242 if len(vk) != len(pok) && len(pok) != 1 { 243 return errors.New("pok length mismatch") 244 } 245 for i := range commitments { 246 if !commitments[i].IsInSubGroup() { 247 return errors.New("commitment subgroup check failed") 248 } 249 if i != 0 && vk[i].G != vk[0].G { 250 return errors.New("parameter mismatch: G2 element") 251 } 252 } 253 for i := range pok { 254 if !pok[i].IsInSubGroup() { 255 return errors.New("pok subgroup check failed") 256 } 257 } 258 259 pairingG1 := make([]curve.G1Affine, len(vk)+1) 260 pairingG2 := make([]curve.G2Affine, len(vk)+1) 261 r := combinationCoeff 262 pairingG1[0] = commitments[0] 263 var rI big.Int 264 for i := range vk { 265 pairingG2[i] = vk[i].GSigma 266 if i != 0 { 267 r.BigInt(&rI) 268 pairingG1[i].ScalarMultiplication(&commitments[i], &rI) 269 if i+1 != len(vk) { 270 r.Mul(&r, &combinationCoeff) 271 } 272 } 273 } 274 if foldedPok, err := new(curve.G1Affine).Fold(pok, combinationCoeff, ecc.MultiExpConfig{NbTasks: 1}); err != nil { 275 return err 276 } else { 277 pairingG1[len(vk)] = *foldedPok 278 } 279 pairingG2[len(vk)] = vk[0].G 280 281 if isOne, err := curve.PairingCheck(pairingG1, pairingG2); err != nil { 282 return err 283 } else if !isOne { 284 return errors.New("proof rejected") 285 } 286 return nil 287 } 288 289 // Marshal 290 291 func (pk *ProvingKey) writeTo(enc *curve.Encoder) (int64, error) { 292 if err := enc.Encode(pk.Basis); err != nil { 293 return enc.BytesWritten(), err 294 } 295 296 err := enc.Encode(pk.BasisExpSigma) 297 298 return enc.BytesWritten(), err 299 } 300 301 func (pk *ProvingKey) WriteTo(w io.Writer) (int64, error) { 302 return pk.writeTo(curve.NewEncoder(w)) 303 } 304 305 func (pk *ProvingKey) WriteRawTo(w io.Writer) (int64, error) { 306 return pk.writeTo(curve.NewEncoder(w, curve.RawEncoding())) 307 } 308 309 func (pk *ProvingKey) ReadFrom(r io.Reader) (int64, error) { 310 dec := curve.NewDecoder(r) 311 312 if err := dec.Decode(&pk.Basis); err != nil { 313 return dec.BytesRead(), err 314 } 315 if err := dec.Decode(&pk.BasisExpSigma); err != nil { 316 return dec.BytesRead(), err 317 } 318 319 if len(pk.Basis) != len(pk.BasisExpSigma) { 320 return dec.BytesRead(), errors.New("commitment/proof length mismatch") 321 } 322 323 return dec.BytesRead(), nil 324 } 325 326 func (vk *VerifyingKey) WriteTo(w io.Writer) (int64, error) { 327 return vk.writeTo(curve.NewEncoder(w)) 328 } 329 330 func (vk *VerifyingKey) WriteRawTo(w io.Writer) (int64, error) { 331 return vk.writeTo(curve.NewEncoder(w, curve.RawEncoding())) 332 } 333 334 func (vk *VerifyingKey) writeTo(enc *curve.Encoder) (int64, error) { 335 var err error 336 337 if err = enc.Encode(&vk.G); err != nil { 338 return enc.BytesWritten(), err 339 } 340 err = enc.Encode(&vk.GSigma) 341 return enc.BytesWritten(), err 342 } 343 344 func (vk *VerifyingKey) ReadFrom(r io.Reader) (int64, error) { 345 return vk.readFrom(r) 346 } 347 348 func (vk *VerifyingKey) UnsafeReadFrom(r io.Reader) (int64, error) { 349 return vk.readFrom(r, curve.NoSubgroupChecks()) 350 } 351 352 func (vk *VerifyingKey) readFrom(r io.Reader, decOptions ...func(*curve.Decoder)) (int64, error) { 353 dec := curve.NewDecoder(r, decOptions...) 354 var err error 355 356 if err = dec.Decode(&vk.G); err != nil { 357 return dec.BytesRead(), err 358 } 359 err = dec.Decode(&vk.GSigma) 360 return dec.BytesRead(), err 361 }