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  }