diff --git a/backend/backend.go b/backend/backend.go index 84a05271ab..aab30f2df1 100644 --- a/backend/backend.go +++ b/backend/backend.go @@ -15,7 +15,12 @@ // Package backend implements Zero Knowledge Proof systems: it consumes circuit compiled with gnark/frontend. package backend -import "github.com/consensys/gnark/constraint/solver" +import ( + "crypto/sha256" + "hash" + + "github.com/consensys/gnark/constraint/solver" +) // ID represent a unique ID for a proving scheme type ID uint16 @@ -53,13 +58,21 @@ type ProverOption func(*ProverConfig) error // ProverConfig is the configuration for the prover with the options applied. type ProverConfig struct { - SolverOpts []solver.Option + SolverOpts []solver.Option + HashToFieldFn hash.Hash + ChallengeHash hash.Hash + KZGFoldingHash hash.Hash } // NewProverConfig returns a default ProverConfig with given prover options opts // applied. func NewProverConfig(opts ...ProverOption) (ProverConfig, error) { - opt := ProverConfig{} + opt := ProverConfig{ + // we cannot initialize HashToFieldFn here as we use different domain + // separation tags for PLONK and Groth16 + ChallengeHash: sha256.New(), + KZGFoldingHash: sha256.New(), + } for _, option := range opts { if err := option(&opt); err != nil { return ProverConfig{}, err @@ -75,3 +88,98 @@ func WithSolverOptions(solverOpts ...solver.Option) ProverOption { return nil } } + +// WithProverHashToFieldFunction changes the hash function used for hashing +// bytes to field. If not set then the default hash function based on RFC 9380 +// is used. Used mainly for compatibility between different systems and +// efficient recursion. +func WithProverHashToFieldFunction(hFunc hash.Hash) ProverOption { + return func(cfg *ProverConfig) error { + cfg.HashToFieldFn = hFunc + return nil + } +} + +// WithProverChallengeHashFunction sets the hash function used for computing +// non-interactive challenges in Fiat-Shamir heuristic. If not set then by +// default SHA2-256 is used. Used mainly for compatibility between different +// systems and efficient recursion. +func WithProverChallengeHashFunction(hFunc hash.Hash) ProverOption { + return func(pc *ProverConfig) error { + pc.ChallengeHash = hFunc + return nil + } +} + +// WithProverKZGFoldingHashFunction sets the hash function used for computing +// the challenge when folding the KZG opening proofs. If not set then by default +// SHA2-256 is used. Used mainly for compatibility between different systems and +// efficient recursion. +func WithProverKZGFoldingHashFunction(hFunc hash.Hash) ProverOption { + return func(pc *ProverConfig) error { + pc.KZGFoldingHash = hFunc + return nil + } +} + +// VerifierOption defines option for altering the behavior of the verifier. See +// the descriptions of functions returning instances of this type for +// implemented options. +type VerifierOption func(*VerifierConfig) error + +// VerifierConfig is the configuration for the verifier with the options applied. +type VerifierConfig struct { + HashToFieldFn hash.Hash + ChallengeHash hash.Hash + KZGFoldingHash hash.Hash +} + +// NewVerifierConfig returns a default [VerifierConfig] with given verifier +// options applied. +func NewVerifierConfig(opts ...VerifierOption) (VerifierConfig, error) { + opt := VerifierConfig{ + // we cannot initialize HashToFieldFn here as we use different domain + // separation tags for PLONK and Groth16 + ChallengeHash: sha256.New(), + KZGFoldingHash: sha256.New(), + } + for _, option := range opts { + if err := option(&opt); err != nil { + return VerifierConfig{}, err + } + } + return opt, nil +} + +// WithVerifierHashToFieldFunction changes the hash function used for hashing +// bytes to field. If not set then the default hash function based on RFC 9380 +// is used. Used mainly for compatibility between different systems and +// efficient recursion. +func WithVerifierHashToFieldFunction(hFunc hash.Hash) VerifierOption { + return func(cfg *VerifierConfig) error { + cfg.HashToFieldFn = hFunc + return nil + } +} + +// WithVerifierChallengeHashFunction sets the hash function used for computing +// non-interactive challenges in Fiat-Shamir heuristic. If not set then by +// default SHA2-256 is used. Used mainly for compatibility between different +// systems and efficient recursion. +func WithVerifierChallengeHashFunction(hFunc hash.Hash) VerifierOption { + return func(pc *VerifierConfig) error { + pc.ChallengeHash = hFunc + return nil + } +} + +// WithVerifierKZGFoldingHashFunction sets the hash function used for computing +// the challenge when folding the KZG opening proofs. If not set then by default +// SHA2-256 is used. Used mainly for compatibility between different systems and +// efficient recursion. +func WithVerifierKZGFoldingHashFunction(hFunc hash.Hash) VerifierOption { + return func(pc *VerifierConfig) error { + pc.KZGFoldingHash = hFunc + return nil + } +} diff --git a/backend/groth16/bls12-377/commitment.go b/backend/groth16/bls12-377/commitment.go deleted file mode 100644 index c267e8a99b..0000000000 --- a/backend/groth16/bls12-377/commitment.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by gnark DO NOT EDIT - -package groth16 - -import ( - curve "github.com/consensys/gnark-crypto/ecc/bls12-377" - "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" - "github.com/consensys/gnark/constraint" - "math/big" -) - -func solveCommitmentWire(commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { - res, err := fr.Hash(constraint.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) - return res[0], err -} diff --git a/backend/groth16/bls12-377/prove.go b/backend/groth16/bls12-377/prove.go index ed7124a557..e715e5e7c9 100644 --- a/backend/groth16/bls12-377/prove.go +++ b/backend/groth16/bls12-377/prove.go @@ -17,10 +17,12 @@ package groth16 import ( + "fmt" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls12-377" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/hash_to_field" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/pedersen" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/groth16/internal" @@ -59,7 +61,10 @@ func (proof *Proof) CurveID() ecc.ID { func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { opt, err := backend.NewProverConfig(opts...) if err != nil { - return nil, err + return nil, fmt.Errorf("new prover config: %w", err) + } + if opt.HashToFieldFn == nil { + opt.HashToFieldFn = hash_to_field.New([]byte(constraint.CommitmentDst)) } log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() @@ -86,8 +91,15 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return err } + opt.HashToFieldFn.Write(constraint.SerializeCommitment(proof.Commitments[i].Marshal(), hashed, (fr.Bits-1)/8+1)) + hashBts := opt.HashToFieldFn.Sum(nil) + opt.HashToFieldFn.Reset() + nbBuf := fr.Bytes + if opt.HashToFieldFn.Size() < fr.Bytes { + nbBuf = opt.HashToFieldFn.Size() + } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitments[i], hashed) + res.SetBytes(hashBts[:nbBuf]) res.BigInt(out[0]) return err } diff --git a/backend/groth16/bls12-377/verify.go b/backend/groth16/bls12-377/verify.go index 3da51fcaee..867ce56708 100644 --- a/backend/groth16/bls12-377/verify.go +++ b/backend/groth16/bls12-377/verify.go @@ -19,15 +19,18 @@ package groth16 import ( "errors" "fmt" + "io" + "time" + "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls12-377" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/hash_to_field" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/pedersen" "github.com/consensys/gnark-crypto/utils" + "github.com/consensys/gnark/backend" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/logger" - "io" - "time" ) var ( @@ -36,7 +39,14 @@ var ( ) // Verify verifies a proof with given VerifyingKey and publicWitness -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { + opt, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("new verifier config: %w", err) + } + if opt.HashToFieldFn == nil { + opt.HashToFieldFn = hash_to_field.New([]byte(constraint.CommitmentDst)) + } nbPublicVars := len(vk.G1.K) - len(vk.PublicAndCommitmentCommitted) @@ -75,12 +85,17 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicAndCommitmentCommitted[i][j]-1].Marshal()) offset += fr.Bytes } - if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { - return err - } else { - publicWitness = append(publicWitness, res[0]) - copy(commitmentsSerialized[i*fr.Bytes:], res[0].Marshal()) + opt.HashToFieldFn.Write(commitmentPrehashSerialized[:offset]) + hashBts := opt.HashToFieldFn.Sum(nil) + opt.HashToFieldFn.Reset() + nbBuf := fr.Bytes + if opt.HashToFieldFn.Size() < fr.Bytes { + nbBuf = opt.HashToFieldFn.Size() } + var res fr.Element + res.SetBytes(hashBts[:nbBuf]) + publicWitness = append(publicWitness, res) + copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) } if folded, err := pedersen.FoldCommitments(proof.Commitments, commitmentsSerialized); err != nil { diff --git a/backend/groth16/bls12-381/commitment.go b/backend/groth16/bls12-381/commitment.go deleted file mode 100644 index 6fcc533b5b..0000000000 --- a/backend/groth16/bls12-381/commitment.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by gnark DO NOT EDIT - -package groth16 - -import ( - curve "github.com/consensys/gnark-crypto/ecc/bls12-381" - "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" - "github.com/consensys/gnark/constraint" - "math/big" -) - -func solveCommitmentWire(commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { - res, err := fr.Hash(constraint.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) - return res[0], err -} diff --git a/backend/groth16/bls12-381/prove.go b/backend/groth16/bls12-381/prove.go index 6e4c0a5227..e79094f0bf 100644 --- a/backend/groth16/bls12-381/prove.go +++ b/backend/groth16/bls12-381/prove.go @@ -17,10 +17,12 @@ package groth16 import ( + "fmt" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls12-381" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/hash_to_field" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/pedersen" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/groth16/internal" @@ -59,7 +61,10 @@ func (proof *Proof) CurveID() ecc.ID { func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { opt, err := backend.NewProverConfig(opts...) if err != nil { - return nil, err + return nil, fmt.Errorf("new prover config: %w", err) + } + if opt.HashToFieldFn == nil { + opt.HashToFieldFn = hash_to_field.New([]byte(constraint.CommitmentDst)) } log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() @@ -86,8 +91,15 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return err } + opt.HashToFieldFn.Write(constraint.SerializeCommitment(proof.Commitments[i].Marshal(), hashed, (fr.Bits-1)/8+1)) + hashBts := opt.HashToFieldFn.Sum(nil) + opt.HashToFieldFn.Reset() + nbBuf := fr.Bytes + if opt.HashToFieldFn.Size() < fr.Bytes { + nbBuf = opt.HashToFieldFn.Size() + } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitments[i], hashed) + res.SetBytes(hashBts[:nbBuf]) res.BigInt(out[0]) return err } diff --git a/backend/groth16/bls12-381/verify.go b/backend/groth16/bls12-381/verify.go index 646e052f42..0bf293f1d3 100644 --- a/backend/groth16/bls12-381/verify.go +++ b/backend/groth16/bls12-381/verify.go @@ -19,15 +19,18 @@ package groth16 import ( "errors" "fmt" + "io" + "time" + "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls12-381" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/hash_to_field" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/pedersen" "github.com/consensys/gnark-crypto/utils" + "github.com/consensys/gnark/backend" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/logger" - "io" - "time" ) var ( @@ -36,7 +39,14 @@ var ( ) // Verify verifies a proof with given VerifyingKey and publicWitness -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { + opt, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("new verifier config: %w", err) + } + if opt.HashToFieldFn == nil { + opt.HashToFieldFn = hash_to_field.New([]byte(constraint.CommitmentDst)) + } nbPublicVars := len(vk.G1.K) - len(vk.PublicAndCommitmentCommitted) @@ -75,12 +85,17 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicAndCommitmentCommitted[i][j]-1].Marshal()) offset += fr.Bytes } - if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { - return err - } else { - publicWitness = append(publicWitness, res[0]) - copy(commitmentsSerialized[i*fr.Bytes:], res[0].Marshal()) + opt.HashToFieldFn.Write(commitmentPrehashSerialized[:offset]) + hashBts := opt.HashToFieldFn.Sum(nil) + opt.HashToFieldFn.Reset() + nbBuf := fr.Bytes + if opt.HashToFieldFn.Size() < fr.Bytes { + nbBuf = opt.HashToFieldFn.Size() } + var res fr.Element + res.SetBytes(hashBts[:nbBuf]) + publicWitness = append(publicWitness, res) + copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) } if folded, err := pedersen.FoldCommitments(proof.Commitments, commitmentsSerialized); err != nil { diff --git a/backend/groth16/bls24-315/commitment.go b/backend/groth16/bls24-315/commitment.go deleted file mode 100644 index fc1a3def96..0000000000 --- a/backend/groth16/bls24-315/commitment.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by gnark DO NOT EDIT - -package groth16 - -import ( - curve "github.com/consensys/gnark-crypto/ecc/bls24-315" - "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" - "github.com/consensys/gnark/constraint" - "math/big" -) - -func solveCommitmentWire(commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { - res, err := fr.Hash(constraint.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) - return res[0], err -} diff --git a/backend/groth16/bls24-315/prove.go b/backend/groth16/bls24-315/prove.go index c464544ad0..8d2d5a3599 100644 --- a/backend/groth16/bls24-315/prove.go +++ b/backend/groth16/bls24-315/prove.go @@ -17,10 +17,12 @@ package groth16 import ( + "fmt" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls24-315" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/hash_to_field" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/pedersen" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/groth16/internal" @@ -59,7 +61,10 @@ func (proof *Proof) CurveID() ecc.ID { func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { opt, err := backend.NewProverConfig(opts...) if err != nil { - return nil, err + return nil, fmt.Errorf("new prover config: %w", err) + } + if opt.HashToFieldFn == nil { + opt.HashToFieldFn = hash_to_field.New([]byte(constraint.CommitmentDst)) } log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() @@ -86,8 +91,15 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return err } + opt.HashToFieldFn.Write(constraint.SerializeCommitment(proof.Commitments[i].Marshal(), hashed, (fr.Bits-1)/8+1)) + hashBts := opt.HashToFieldFn.Sum(nil) + opt.HashToFieldFn.Reset() + nbBuf := fr.Bytes + if opt.HashToFieldFn.Size() < fr.Bytes { + nbBuf = opt.HashToFieldFn.Size() + } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitments[i], hashed) + res.SetBytes(hashBts[:nbBuf]) res.BigInt(out[0]) return err } diff --git a/backend/groth16/bls24-315/verify.go b/backend/groth16/bls24-315/verify.go index 6e85b70ecf..2c95a54d0d 100644 --- a/backend/groth16/bls24-315/verify.go +++ b/backend/groth16/bls24-315/verify.go @@ -19,15 +19,18 @@ package groth16 import ( "errors" "fmt" + "io" + "time" + "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls24-315" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/hash_to_field" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/pedersen" "github.com/consensys/gnark-crypto/utils" + "github.com/consensys/gnark/backend" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/logger" - "io" - "time" ) var ( @@ -36,7 +39,14 @@ var ( ) // Verify verifies a proof with given VerifyingKey and publicWitness -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { + opt, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("new verifier config: %w", err) + } + if opt.HashToFieldFn == nil { + opt.HashToFieldFn = hash_to_field.New([]byte(constraint.CommitmentDst)) + } nbPublicVars := len(vk.G1.K) - len(vk.PublicAndCommitmentCommitted) @@ -75,12 +85,17 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicAndCommitmentCommitted[i][j]-1].Marshal()) offset += fr.Bytes } - if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { - return err - } else { - publicWitness = append(publicWitness, res[0]) - copy(commitmentsSerialized[i*fr.Bytes:], res[0].Marshal()) + opt.HashToFieldFn.Write(commitmentPrehashSerialized[:offset]) + hashBts := opt.HashToFieldFn.Sum(nil) + opt.HashToFieldFn.Reset() + nbBuf := fr.Bytes + if opt.HashToFieldFn.Size() < fr.Bytes { + nbBuf = opt.HashToFieldFn.Size() } + var res fr.Element + res.SetBytes(hashBts[:nbBuf]) + publicWitness = append(publicWitness, res) + copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) } if folded, err := pedersen.FoldCommitments(proof.Commitments, commitmentsSerialized); err != nil { diff --git a/backend/groth16/bls24-317/commitment.go b/backend/groth16/bls24-317/commitment.go deleted file mode 100644 index 05d71ba172..0000000000 --- a/backend/groth16/bls24-317/commitment.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by gnark DO NOT EDIT - -package groth16 - -import ( - curve "github.com/consensys/gnark-crypto/ecc/bls24-317" - "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" - "github.com/consensys/gnark/constraint" - "math/big" -) - -func solveCommitmentWire(commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { - res, err := fr.Hash(constraint.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) - return res[0], err -} diff --git a/backend/groth16/bls24-317/prove.go b/backend/groth16/bls24-317/prove.go index 10f38c5f77..41aa6c80b0 100644 --- a/backend/groth16/bls24-317/prove.go +++ b/backend/groth16/bls24-317/prove.go @@ -17,10 +17,12 @@ package groth16 import ( + "fmt" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls24-317" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/hash_to_field" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/pedersen" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/groth16/internal" @@ -59,7 +61,10 @@ func (proof *Proof) CurveID() ecc.ID { func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { opt, err := backend.NewProverConfig(opts...) if err != nil { - return nil, err + return nil, fmt.Errorf("new prover config: %w", err) + } + if opt.HashToFieldFn == nil { + opt.HashToFieldFn = hash_to_field.New([]byte(constraint.CommitmentDst)) } log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() @@ -86,8 +91,15 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return err } + opt.HashToFieldFn.Write(constraint.SerializeCommitment(proof.Commitments[i].Marshal(), hashed, (fr.Bits-1)/8+1)) + hashBts := opt.HashToFieldFn.Sum(nil) + opt.HashToFieldFn.Reset() + nbBuf := fr.Bytes + if opt.HashToFieldFn.Size() < fr.Bytes { + nbBuf = opt.HashToFieldFn.Size() + } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitments[i], hashed) + res.SetBytes(hashBts[:nbBuf]) res.BigInt(out[0]) return err } diff --git a/backend/groth16/bls24-317/verify.go b/backend/groth16/bls24-317/verify.go index 3affc23113..f4c92dc687 100644 --- a/backend/groth16/bls24-317/verify.go +++ b/backend/groth16/bls24-317/verify.go @@ -19,15 +19,18 @@ package groth16 import ( "errors" "fmt" + "io" + "time" + "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls24-317" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/hash_to_field" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/pedersen" "github.com/consensys/gnark-crypto/utils" + "github.com/consensys/gnark/backend" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/logger" - "io" - "time" ) var ( @@ -36,7 +39,14 @@ var ( ) // Verify verifies a proof with given VerifyingKey and publicWitness -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { + opt, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("new verifier config: %w", err) + } + if opt.HashToFieldFn == nil { + opt.HashToFieldFn = hash_to_field.New([]byte(constraint.CommitmentDst)) + } nbPublicVars := len(vk.G1.K) - len(vk.PublicAndCommitmentCommitted) @@ -75,12 +85,17 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicAndCommitmentCommitted[i][j]-1].Marshal()) offset += fr.Bytes } - if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { - return err - } else { - publicWitness = append(publicWitness, res[0]) - copy(commitmentsSerialized[i*fr.Bytes:], res[0].Marshal()) + opt.HashToFieldFn.Write(commitmentPrehashSerialized[:offset]) + hashBts := opt.HashToFieldFn.Sum(nil) + opt.HashToFieldFn.Reset() + nbBuf := fr.Bytes + if opt.HashToFieldFn.Size() < fr.Bytes { + nbBuf = opt.HashToFieldFn.Size() } + var res fr.Element + res.SetBytes(hashBts[:nbBuf]) + publicWitness = append(publicWitness, res) + copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) } if folded, err := pedersen.FoldCommitments(proof.Commitments, commitmentsSerialized); err != nil { diff --git a/backend/groth16/bn254/commitment.go b/backend/groth16/bn254/commitment.go deleted file mode 100644 index 435a7c058c..0000000000 --- a/backend/groth16/bn254/commitment.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by gnark DO NOT EDIT - -package groth16 - -import ( - curve "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark-crypto/ecc/bn254/fr" - "github.com/consensys/gnark/constraint" - "math/big" -) - -func solveCommitmentWire(commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { - res, err := fr.Hash(constraint.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) - return res[0], err -} diff --git a/backend/groth16/bn254/prove.go b/backend/groth16/bn254/prove.go index 42ec4de8b9..7bb46ef26a 100644 --- a/backend/groth16/bn254/prove.go +++ b/backend/groth16/bn254/prove.go @@ -17,10 +17,12 @@ package groth16 import ( + "fmt" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/hash_to_field" "github.com/consensys/gnark-crypto/ecc/bn254/fr/pedersen" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/groth16/internal" @@ -59,7 +61,10 @@ func (proof *Proof) CurveID() ecc.ID { func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { opt, err := backend.NewProverConfig(opts...) if err != nil { - return nil, err + return nil, fmt.Errorf("new prover config: %w", err) + } + if opt.HashToFieldFn == nil { + opt.HashToFieldFn = hash_to_field.New([]byte(constraint.CommitmentDst)) } log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() @@ -86,8 +91,15 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return err } + opt.HashToFieldFn.Write(constraint.SerializeCommitment(proof.Commitments[i].Marshal(), hashed, (fr.Bits-1)/8+1)) + hashBts := opt.HashToFieldFn.Sum(nil) + opt.HashToFieldFn.Reset() + nbBuf := fr.Bytes + if opt.HashToFieldFn.Size() < fr.Bytes { + nbBuf = opt.HashToFieldFn.Size() + } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitments[i], hashed) + res.SetBytes(hashBts[:nbBuf]) res.BigInt(out[0]) return err } diff --git a/backend/groth16/bn254/verify.go b/backend/groth16/bn254/verify.go index 7d68d68a17..14eda65ed6 100644 --- a/backend/groth16/bn254/verify.go +++ b/backend/groth16/bn254/verify.go @@ -19,16 +19,19 @@ package groth16 import ( "errors" "fmt" + "io" + "text/template" + "time" + "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/hash_to_field" "github.com/consensys/gnark-crypto/ecc/bn254/fr/pedersen" "github.com/consensys/gnark-crypto/utils" + "github.com/consensys/gnark/backend" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/logger" - "io" - "text/template" - "time" ) var ( @@ -37,7 +40,14 @@ var ( ) // Verify verifies a proof with given VerifyingKey and publicWitness -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { + opt, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("new verifier config: %w", err) + } + if opt.HashToFieldFn == nil { + opt.HashToFieldFn = hash_to_field.New([]byte(constraint.CommitmentDst)) + } nbPublicVars := len(vk.G1.K) - len(vk.PublicAndCommitmentCommitted) @@ -76,12 +86,17 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicAndCommitmentCommitted[i][j]-1].Marshal()) offset += fr.Bytes } - if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { - return err - } else { - publicWitness = append(publicWitness, res[0]) - copy(commitmentsSerialized[i*fr.Bytes:], res[0].Marshal()) + opt.HashToFieldFn.Write(commitmentPrehashSerialized[:offset]) + hashBts := opt.HashToFieldFn.Sum(nil) + opt.HashToFieldFn.Reset() + nbBuf := fr.Bytes + if opt.HashToFieldFn.Size() < fr.Bytes { + nbBuf = opt.HashToFieldFn.Size() } + var res fr.Element + res.SetBytes(hashBts[:nbBuf]) + publicWitness = append(publicWitness, res) + copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) } if folded, err := pedersen.FoldCommitments(proof.Commitments, commitmentsSerialized); err != nil { diff --git a/backend/groth16/bw6-633/commitment.go b/backend/groth16/bw6-633/commitment.go deleted file mode 100644 index f8af92e4fc..0000000000 --- a/backend/groth16/bw6-633/commitment.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by gnark DO NOT EDIT - -package groth16 - -import ( - curve "github.com/consensys/gnark-crypto/ecc/bw6-633" - "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" - "github.com/consensys/gnark/constraint" - "math/big" -) - -func solveCommitmentWire(commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { - res, err := fr.Hash(constraint.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) - return res[0], err -} diff --git a/backend/groth16/bw6-633/prove.go b/backend/groth16/bw6-633/prove.go index b92dbb6943..70c8087b96 100644 --- a/backend/groth16/bw6-633/prove.go +++ b/backend/groth16/bw6-633/prove.go @@ -17,10 +17,12 @@ package groth16 import ( + "fmt" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bw6-633" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/hash_to_field" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/pedersen" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/groth16/internal" @@ -59,7 +61,10 @@ func (proof *Proof) CurveID() ecc.ID { func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { opt, err := backend.NewProverConfig(opts...) if err != nil { - return nil, err + return nil, fmt.Errorf("new prover config: %w", err) + } + if opt.HashToFieldFn == nil { + opt.HashToFieldFn = hash_to_field.New([]byte(constraint.CommitmentDst)) } log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() @@ -86,8 +91,15 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return err } + opt.HashToFieldFn.Write(constraint.SerializeCommitment(proof.Commitments[i].Marshal(), hashed, (fr.Bits-1)/8+1)) + hashBts := opt.HashToFieldFn.Sum(nil) + opt.HashToFieldFn.Reset() + nbBuf := fr.Bytes + if opt.HashToFieldFn.Size() < fr.Bytes { + nbBuf = opt.HashToFieldFn.Size() + } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitments[i], hashed) + res.SetBytes(hashBts[:nbBuf]) res.BigInt(out[0]) return err } diff --git a/backend/groth16/bw6-633/verify.go b/backend/groth16/bw6-633/verify.go index c32a71e6a6..3bfaaffd39 100644 --- a/backend/groth16/bw6-633/verify.go +++ b/backend/groth16/bw6-633/verify.go @@ -19,15 +19,18 @@ package groth16 import ( "errors" "fmt" + "io" + "time" + "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bw6-633" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/hash_to_field" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/pedersen" "github.com/consensys/gnark-crypto/utils" + "github.com/consensys/gnark/backend" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/logger" - "io" - "time" ) var ( @@ -36,7 +39,14 @@ var ( ) // Verify verifies a proof with given VerifyingKey and publicWitness -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { + opt, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("new verifier config: %w", err) + } + if opt.HashToFieldFn == nil { + opt.HashToFieldFn = hash_to_field.New([]byte(constraint.CommitmentDst)) + } nbPublicVars := len(vk.G1.K) - len(vk.PublicAndCommitmentCommitted) @@ -75,12 +85,17 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicAndCommitmentCommitted[i][j]-1].Marshal()) offset += fr.Bytes } - if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { - return err - } else { - publicWitness = append(publicWitness, res[0]) - copy(commitmentsSerialized[i*fr.Bytes:], res[0].Marshal()) + opt.HashToFieldFn.Write(commitmentPrehashSerialized[:offset]) + hashBts := opt.HashToFieldFn.Sum(nil) + opt.HashToFieldFn.Reset() + nbBuf := fr.Bytes + if opt.HashToFieldFn.Size() < fr.Bytes { + nbBuf = opt.HashToFieldFn.Size() } + var res fr.Element + res.SetBytes(hashBts[:nbBuf]) + publicWitness = append(publicWitness, res) + copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) } if folded, err := pedersen.FoldCommitments(proof.Commitments, commitmentsSerialized); err != nil { diff --git a/backend/groth16/bw6-761/commitment.go b/backend/groth16/bw6-761/commitment.go deleted file mode 100644 index 5c357c24ad..0000000000 --- a/backend/groth16/bw6-761/commitment.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by gnark DO NOT EDIT - -package groth16 - -import ( - curve "github.com/consensys/gnark-crypto/ecc/bw6-761" - "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" - "github.com/consensys/gnark/constraint" - "math/big" -) - -func solveCommitmentWire(commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { - res, err := fr.Hash(constraint.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) - return res[0], err -} diff --git a/backend/groth16/bw6-761/prove.go b/backend/groth16/bw6-761/prove.go index 3ee6b9ad0f..814c4057ad 100644 --- a/backend/groth16/bw6-761/prove.go +++ b/backend/groth16/bw6-761/prove.go @@ -17,10 +17,12 @@ package groth16 import ( + "fmt" "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bw6-761" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fft" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/hash_to_field" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/pedersen" "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/groth16/internal" @@ -59,7 +61,10 @@ func (proof *Proof) CurveID() ecc.ID { func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { opt, err := backend.NewProverConfig(opts...) if err != nil { - return nil, err + return nil, fmt.Errorf("new prover config: %w", err) + } + if opt.HashToFieldFn == nil { + opt.HashToFieldFn = hash_to_field.New([]byte(constraint.CommitmentDst)) } log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() @@ -86,8 +91,15 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return err } + opt.HashToFieldFn.Write(constraint.SerializeCommitment(proof.Commitments[i].Marshal(), hashed, (fr.Bits-1)/8+1)) + hashBts := opt.HashToFieldFn.Sum(nil) + opt.HashToFieldFn.Reset() + nbBuf := fr.Bytes + if opt.HashToFieldFn.Size() < fr.Bytes { + nbBuf = opt.HashToFieldFn.Size() + } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitments[i], hashed) + res.SetBytes(hashBts[:nbBuf]) res.BigInt(out[0]) return err } diff --git a/backend/groth16/bw6-761/verify.go b/backend/groth16/bw6-761/verify.go index ca49685a5e..f08d631d62 100644 --- a/backend/groth16/bw6-761/verify.go +++ b/backend/groth16/bw6-761/verify.go @@ -19,15 +19,18 @@ package groth16 import ( "errors" "fmt" + "io" + "time" + "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bw6-761" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/hash_to_field" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/pedersen" "github.com/consensys/gnark-crypto/utils" + "github.com/consensys/gnark/backend" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/logger" - "io" - "time" ) var ( @@ -36,7 +39,14 @@ var ( ) // Verify verifies a proof with given VerifyingKey and publicWitness -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { + opt, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("new verifier config: %w", err) + } + if opt.HashToFieldFn == nil { + opt.HashToFieldFn = hash_to_field.New([]byte(constraint.CommitmentDst)) + } nbPublicVars := len(vk.G1.K) - len(vk.PublicAndCommitmentCommitted) @@ -75,12 +85,17 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicAndCommitmentCommitted[i][j]-1].Marshal()) offset += fr.Bytes } - if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { - return err - } else { - publicWitness = append(publicWitness, res[0]) - copy(commitmentsSerialized[i*fr.Bytes:], res[0].Marshal()) + opt.HashToFieldFn.Write(commitmentPrehashSerialized[:offset]) + hashBts := opt.HashToFieldFn.Sum(nil) + opt.HashToFieldFn.Reset() + nbBuf := fr.Bytes + if opt.HashToFieldFn.Size() < fr.Bytes { + nbBuf = opt.HashToFieldFn.Size() } + var res fr.Element + res.SetBytes(hashBts[:nbBuf]) + publicWitness = append(publicWitness, res) + copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) } if folded, err := pedersen.FoldCommitments(proof.Commitments, commitmentsSerialized); err != nil { diff --git a/backend/groth16/groth16.go b/backend/groth16/groth16.go index 41e0f63c7e..823e7c3f4b 100644 --- a/backend/groth16/groth16.go +++ b/backend/groth16/groth16.go @@ -109,7 +109,7 @@ type VerifyingKey interface { } // Verify runs the groth16.Verify algorithm on provided proof with given witness -func Verify(proof Proof, vk VerifyingKey, publicWitness witness.Witness) error { +func Verify(proof Proof, vk VerifyingKey, publicWitness witness.Witness, opts ...backend.VerifierOption) error { switch _proof := proof.(type) { case *groth16_bls12377.Proof: @@ -117,43 +117,43 @@ func Verify(proof Proof, vk VerifyingKey, publicWitness witness.Witness) error { if !ok { return witness.ErrInvalidWitness } - return groth16_bls12377.Verify(_proof, vk.(*groth16_bls12377.VerifyingKey), w) + return groth16_bls12377.Verify(_proof, vk.(*groth16_bls12377.VerifyingKey), w, opts...) case *groth16_bls12381.Proof: w, ok := publicWitness.Vector().(fr_bls12381.Vector) if !ok { return witness.ErrInvalidWitness } - return groth16_bls12381.Verify(_proof, vk.(*groth16_bls12381.VerifyingKey), w) + return groth16_bls12381.Verify(_proof, vk.(*groth16_bls12381.VerifyingKey), w, opts...) case *groth16_bn254.Proof: w, ok := publicWitness.Vector().(fr_bn254.Vector) if !ok { return witness.ErrInvalidWitness } - return groth16_bn254.Verify(_proof, vk.(*groth16_bn254.VerifyingKey), w) + return groth16_bn254.Verify(_proof, vk.(*groth16_bn254.VerifyingKey), w, opts...) case *groth16_bw6761.Proof: w, ok := publicWitness.Vector().(fr_bw6761.Vector) if !ok { return witness.ErrInvalidWitness } - return groth16_bw6761.Verify(_proof, vk.(*groth16_bw6761.VerifyingKey), w) + return groth16_bw6761.Verify(_proof, vk.(*groth16_bw6761.VerifyingKey), w, opts...) case *groth16_bls24317.Proof: w, ok := publicWitness.Vector().(fr_bls24317.Vector) if !ok { return witness.ErrInvalidWitness } - return groth16_bls24317.Verify(_proof, vk.(*groth16_bls24317.VerifyingKey), w) + return groth16_bls24317.Verify(_proof, vk.(*groth16_bls24317.VerifyingKey), w, opts...) case *groth16_bls24315.Proof: w, ok := publicWitness.Vector().(fr_bls24315.Vector) if !ok { return witness.ErrInvalidWitness } - return groth16_bls24315.Verify(_proof, vk.(*groth16_bls24315.VerifyingKey), w) + return groth16_bls24315.Verify(_proof, vk.(*groth16_bls24315.VerifyingKey), w, opts...) case *groth16_bw6633.Proof: w, ok := publicWitness.Vector().(fr_bw6633.Vector) if !ok { return witness.ErrInvalidWitness } - return groth16_bw6633.Verify(_proof, vk.(*groth16_bw6633.VerifyingKey), w) + return groth16_bw6633.Verify(_proof, vk.(*groth16_bw6633.VerifyingKey), w, opts...) default: panic("unrecognized R1CS curve type") } diff --git a/backend/groth16/groth16_test.go b/backend/groth16/groth16_test.go index 24fca03aed..027dc388d2 100644 --- a/backend/groth16/groth16_test.go +++ b/backend/groth16/groth16_test.go @@ -1,17 +1,56 @@ package groth16_test import ( + "fmt" "math/big" "testing" "github.com/consensys/gnark" "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/groth16" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/test" ) +func TestCustomHashToField(t *testing.T) { + assert := test.NewAssert(t) + assignment := &commitmentCircuit{X: 1} + for _, curve := range getCurves() { + assert.Run(func(assert *test.Assert) { + ccs, err := frontend.Compile(curve.ScalarField(), r1cs.NewBuilder, &commitmentCircuit{}) + assert.NoError(err) + pk, vk, err := groth16.Setup(ccs) + assert.NoError(err) + witness, err := frontend.NewWitness(assignment, curve.ScalarField()) + assert.NoError(err) + assert.Run(func(assert *test.Assert) { + proof, err := groth16.Prove(ccs, pk, witness, backend.WithProverHashToFieldFunction(constantHash{})) + assert.NoError(err) + pubWitness, err := witness.Public() + assert.NoError(err) + err = groth16.Verify(proof, vk, pubWitness, backend.WithVerifierHashToFieldFunction(constantHash{})) + assert.NoError(err) + }, "custom success") + assert.Run(func(assert *test.Assert) { + proof, err := groth16.Prove(ccs, pk, witness, backend.WithProverHashToFieldFunction(constantHash{})) + assert.NoError(err) + pubWitness, err := witness.Public() + assert.NoError(err) + err = groth16.Verify(proof, vk, pubWitness) + assert.Error(err) + }, "prover_only") + assert.Run(func(assert *test.Assert) { + proof, err := groth16.Prove(ccs, pk, witness) + assert.Error(err) + _ = proof + }, "verifier_only") + }, curve.String()) + } +} + //--------------------// // benches // //--------------------// @@ -116,6 +155,27 @@ func referenceCircuit(curve ecc.ID) (constraint.ConstraintSystem, frontend.Circu return r1cs, &good } +type commitmentCircuit struct { + X frontend.Variable +} + +func (c *commitmentCircuit) Define(api frontend.API) error { + cmt, err := api.(frontend.Committer).Commit(c.X) + if err != nil { + return fmt.Errorf("commit: %w", err) + } + api.AssertIsEqual(cmt, "0xaabbcc") + return nil +} + +type constantHash struct{} + +func (h constantHash) Write(p []byte) (n int, err error) { return len(p), nil } +func (h constantHash) Sum(b []byte) []byte { return []byte{0xaa, 0xbb, 0xcc} } +func (h constantHash) Reset() {} +func (h constantHash) Size() int { return 3 } +func (h constantHash) BlockSize() int { return 32 } + func getCurves() []ecc.ID { if testing.Short() { return []ecc.ID{ecc.BN254} diff --git a/backend/plonk/bls12-377/prove.go b/backend/plonk/bls12-377/prove.go index 3a5e5fcd13..46346775c5 100644 --- a/backend/plonk/bls12-377/prove.go +++ b/backend/plonk/bls12-377/prove.go @@ -18,9 +18,8 @@ package plonk import ( "context" - "crypto/sha256" "errors" - "golang.org/x/sync/errgroup" + "fmt" "hash" "math/big" "math/bits" @@ -28,24 +27,25 @@ import ( "sync" "time" - "github.com/consensys/gnark/backend/witness" + "golang.org/x/sync/errgroup" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" - curve "github.com/consensys/gnark-crypto/ecc/bls12-377" - "github.com/consensys/gnark-crypto/ecc/bls12-377/kzg" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fft" - + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/hash_to_field" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/iop" - cs "github.com/consensys/gnark/constraint/bls12-377" - "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark-crypto/ecc/bls12-377/kzg" + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" + cs "github.com/consensys/gnark/constraint/bls12-377" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" @@ -122,14 +122,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // parse the options opt, err := backend.NewProverConfig(opts...) if err != nil { - return nil, err + return nil, fmt.Errorf("get prover options: %w", err) } start := time.Now() // init instance g, ctx := errgroup.WithContext(context.Background()) - instance := newInstance(ctx, spr, pk, fullWitness, &opt) + instance, err := newInstance(ctx, spr, pk, fullWitness, &opt) + if err != nil { + return nil, fmt.Errorf("new instance: %w", err) + } // solve constraints g.Go(instance.solveConstraints) @@ -181,8 +184,9 @@ type instance struct { spr *cs.SparseR1CS opt *backend.ProverConfig - fs fiatshamir.Transcript - hFunc hash.Hash + fs fiatshamir.Transcript + kzgFoldingHash hash.Hash // for KZG folding + htfFunc hash.Hash // hash to field function // polynomials x []*iop.Polynomial // x stores tracks the polynomial we need @@ -223,8 +227,10 @@ type instance struct { chGammaBeta chan struct{} } -func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts *backend.ProverConfig) instance { - hFunc := sha256.New() +func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts *backend.ProverConfig) (*instance, error) { + if opts.HashToFieldFn == nil { + opts.HashToFieldFn = hash_to_field.New([]byte("BSB22-Plonk")) + } s := instance{ ctx: ctx, pk: pk, @@ -233,8 +239,9 @@ func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWi opt: opts, fullWitness: fullWitness, bp: make([]*iop.Polynomial, nb_blinding_polynomials), - fs: fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta"), - hFunc: hFunc, + fs: fiatshamir.NewTranscript(opts.ChallengeHash, "gamma", "beta", "alpha", "zeta"), + kzgFoldingHash: opts.KZGFoldingHash, + htfFunc: opts.HashToFieldFn, chLRO: make(chan struct{}, 1), chQk: make(chan struct{}, 1), chbp: make(chan struct{}, 1), @@ -251,7 +258,7 @@ func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWi s.setupGKRHints() s.x = make([]*iop.Polynomial, id_Qci+2*len(s.commitmentInfo)) - return s + return &s, nil } func (s *instance) initComputeNumerator() error { @@ -309,6 +316,8 @@ func (s *instance) initBSB22Commitments() { // Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg func (s *instance) bsb22Hint(commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { + var err error + res := &s.commitmentVal[commDepth] commitmentInfo := s.spr.CommitmentInfo.(constraint.PlonkCommitments)[commDepth] @@ -317,10 +326,6 @@ func (s *instance) bsb22Hint(commDepth int) solver.Hint { for i := range ins { committedValues[offset+commitmentInfo.Committed[i]].SetBigInt(ins[i]) } - var ( - err error - hashRes []fr.Element - ) if _, err = committedValues[offset+commitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } @@ -333,10 +338,14 @@ func (s *instance) bsb22Hint(commDepth int) solver.Hint { } s.cCommitments[commDepth].ToCanonical(&s.pk.Domain[0]).ToRegular() - if hashRes, err = fr.Hash(s.proof.Bsb22Commitments[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err + s.htfFunc.Write(s.proof.Bsb22Commitments[commDepth].Marshal()) + hashBts := s.htfFunc.Sum(nil) + s.htfFunc.Reset() + nbBuf := fr.Bytes + if s.htfFunc.Size() < fr.Bytes { + nbBuf = s.htfFunc.Size() } - res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + res.SetBytes(hashBts[:nbBuf]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses res.BigInt(outs[0]) return nil @@ -816,7 +825,7 @@ func (s *instance) batchOpening() error { polysToOpen, digestsToOpen, s.zeta, - s.hFunc, + s.kzgFoldingHash, s.pk.Kzg, s.proof.ZShiftedOpening.ClaimedValue.Marshal(), ) diff --git a/backend/plonk/bls12-377/verify.go b/backend/plonk/bls12-377/verify.go index eaff75894f..8b7fbdf3a4 100644 --- a/backend/plonk/bls12-377/verify.go +++ b/backend/plonk/bls12-377/verify.go @@ -17,20 +17,24 @@ package plonk import ( - "crypto/sha256" "errors" + "fmt" "io" "math/big" - "time" - "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "time" - "github.com/consensys/gnark-crypto/ecc/bls12-377/kzg" + "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls12-377" - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/hash_to_field" + + "github.com/consensys/gnark-crypto/ecc/bls12-377/kzg" + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend" "github.com/consensys/gnark/logger" ) @@ -38,19 +42,20 @@ var ( errWrongClaimedQuotient = errors.New("claimed quotient is not as expected") ) -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { log := logger.Logger().With().Str("curve", "bls12-377").Str("backend", "plonk").Logger() start := time.Now() + cfg, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("create backend config: %w", err) + } if len(proof.Bsb22Commitments) != len(vk.Qcp) { return errors.New("BSB22 Commitment number mismatch") } - // pick a hash function to derive the challenge (the same as in the prover) - hFunc := sha256.New() - // transcript to derive the challenge - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta") // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. @@ -119,11 +124,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } } + if cfg.HashToFieldFn == nil { + cfg.HashToFieldFn = hash_to_field.New([]byte("BSB22-Plonk")) + } + var hashBts []byte + var hashedCmt fr.Element + nbBuf := fr.Bytes + if cfg.HashToFieldFn.Size() < fr.Bytes { + nbBuf = cfg.HashToFieldFn.Size() + } for i := range vk.CommitmentConstraintIndexes { - var hashRes []fr.Element - if hashRes, err = fr.Hash(proof.Bsb22Commitments[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err - } + cfg.HashToFieldFn.Write(proof.Bsb22Commitments[i].Marshal()) + hashBts = cfg.HashToFieldFn.Sum(hashBts[0:]) + cfg.HashToFieldFn.Reset() + hashedCmt.SetBytes(hashBts[:nbBuf]) // Computing L_{CommitmentIndex} @@ -136,7 +150,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) Mul(&lagrange, &lagrangeOne) // wⁱ/n (ζⁿ-1)/(ζ-wⁱ) - xiLi.Mul(&lagrange, &hashRes[0]) + xiLi.Mul(&lagrange, &hashedCmt) pi.Add(&pi, &xiLi) } } @@ -250,7 +264,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { digestsToFold, &proof.BatchedProof, zeta, - hFunc, + cfg.KZGFoldingHash, zu.Marshal(), ) if err != nil { diff --git a/backend/plonk/bls12-381/prove.go b/backend/plonk/bls12-381/prove.go index 8bba0b403d..cd6282fcdf 100644 --- a/backend/plonk/bls12-381/prove.go +++ b/backend/plonk/bls12-381/prove.go @@ -18,9 +18,8 @@ package plonk import ( "context" - "crypto/sha256" "errors" - "golang.org/x/sync/errgroup" + "fmt" "hash" "math/big" "math/bits" @@ -28,24 +27,25 @@ import ( "sync" "time" - "github.com/consensys/gnark/backend/witness" + "golang.org/x/sync/errgroup" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" - curve "github.com/consensys/gnark-crypto/ecc/bls12-381" - "github.com/consensys/gnark-crypto/ecc/bls12-381/kzg" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fft" - + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/hash_to_field" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/iop" - cs "github.com/consensys/gnark/constraint/bls12-381" - "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark-crypto/ecc/bls12-381/kzg" + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" + cs "github.com/consensys/gnark/constraint/bls12-381" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" @@ -122,14 +122,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // parse the options opt, err := backend.NewProverConfig(opts...) if err != nil { - return nil, err + return nil, fmt.Errorf("get prover options: %w", err) } start := time.Now() // init instance g, ctx := errgroup.WithContext(context.Background()) - instance := newInstance(ctx, spr, pk, fullWitness, &opt) + instance, err := newInstance(ctx, spr, pk, fullWitness, &opt) + if err != nil { + return nil, fmt.Errorf("new instance: %w", err) + } // solve constraints g.Go(instance.solveConstraints) @@ -181,8 +184,9 @@ type instance struct { spr *cs.SparseR1CS opt *backend.ProverConfig - fs fiatshamir.Transcript - hFunc hash.Hash + fs fiatshamir.Transcript + kzgFoldingHash hash.Hash // for KZG folding + htfFunc hash.Hash // hash to field function // polynomials x []*iop.Polynomial // x stores tracks the polynomial we need @@ -223,8 +227,10 @@ type instance struct { chGammaBeta chan struct{} } -func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts *backend.ProverConfig) instance { - hFunc := sha256.New() +func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts *backend.ProverConfig) (*instance, error) { + if opts.HashToFieldFn == nil { + opts.HashToFieldFn = hash_to_field.New([]byte("BSB22-Plonk")) + } s := instance{ ctx: ctx, pk: pk, @@ -233,8 +239,9 @@ func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWi opt: opts, fullWitness: fullWitness, bp: make([]*iop.Polynomial, nb_blinding_polynomials), - fs: fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta"), - hFunc: hFunc, + fs: fiatshamir.NewTranscript(opts.ChallengeHash, "gamma", "beta", "alpha", "zeta"), + kzgFoldingHash: opts.KZGFoldingHash, + htfFunc: opts.HashToFieldFn, chLRO: make(chan struct{}, 1), chQk: make(chan struct{}, 1), chbp: make(chan struct{}, 1), @@ -251,7 +258,7 @@ func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWi s.setupGKRHints() s.x = make([]*iop.Polynomial, id_Qci+2*len(s.commitmentInfo)) - return s + return &s, nil } func (s *instance) initComputeNumerator() error { @@ -309,6 +316,8 @@ func (s *instance) initBSB22Commitments() { // Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg func (s *instance) bsb22Hint(commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { + var err error + res := &s.commitmentVal[commDepth] commitmentInfo := s.spr.CommitmentInfo.(constraint.PlonkCommitments)[commDepth] @@ -317,10 +326,6 @@ func (s *instance) bsb22Hint(commDepth int) solver.Hint { for i := range ins { committedValues[offset+commitmentInfo.Committed[i]].SetBigInt(ins[i]) } - var ( - err error - hashRes []fr.Element - ) if _, err = committedValues[offset+commitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } @@ -333,10 +338,14 @@ func (s *instance) bsb22Hint(commDepth int) solver.Hint { } s.cCommitments[commDepth].ToCanonical(&s.pk.Domain[0]).ToRegular() - if hashRes, err = fr.Hash(s.proof.Bsb22Commitments[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err + s.htfFunc.Write(s.proof.Bsb22Commitments[commDepth].Marshal()) + hashBts := s.htfFunc.Sum(nil) + s.htfFunc.Reset() + nbBuf := fr.Bytes + if s.htfFunc.Size() < fr.Bytes { + nbBuf = s.htfFunc.Size() } - res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + res.SetBytes(hashBts[:nbBuf]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses res.BigInt(outs[0]) return nil @@ -816,7 +825,7 @@ func (s *instance) batchOpening() error { polysToOpen, digestsToOpen, s.zeta, - s.hFunc, + s.kzgFoldingHash, s.pk.Kzg, s.proof.ZShiftedOpening.ClaimedValue.Marshal(), ) diff --git a/backend/plonk/bls12-381/verify.go b/backend/plonk/bls12-381/verify.go index ee0e63b9bd..2b3eeef6c1 100644 --- a/backend/plonk/bls12-381/verify.go +++ b/backend/plonk/bls12-381/verify.go @@ -17,20 +17,24 @@ package plonk import ( - "crypto/sha256" "errors" + "fmt" "io" "math/big" - "time" - "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "time" - "github.com/consensys/gnark-crypto/ecc/bls12-381/kzg" + "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls12-381" - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/hash_to_field" + + "github.com/consensys/gnark-crypto/ecc/bls12-381/kzg" + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend" "github.com/consensys/gnark/logger" ) @@ -38,19 +42,20 @@ var ( errWrongClaimedQuotient = errors.New("claimed quotient is not as expected") ) -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { log := logger.Logger().With().Str("curve", "bls12-381").Str("backend", "plonk").Logger() start := time.Now() + cfg, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("create backend config: %w", err) + } if len(proof.Bsb22Commitments) != len(vk.Qcp) { return errors.New("BSB22 Commitment number mismatch") } - // pick a hash function to derive the challenge (the same as in the prover) - hFunc := sha256.New() - // transcript to derive the challenge - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta") // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. @@ -119,11 +124,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } } + if cfg.HashToFieldFn == nil { + cfg.HashToFieldFn = hash_to_field.New([]byte("BSB22-Plonk")) + } + var hashBts []byte + var hashedCmt fr.Element + nbBuf := fr.Bytes + if cfg.HashToFieldFn.Size() < fr.Bytes { + nbBuf = cfg.HashToFieldFn.Size() + } for i := range vk.CommitmentConstraintIndexes { - var hashRes []fr.Element - if hashRes, err = fr.Hash(proof.Bsb22Commitments[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err - } + cfg.HashToFieldFn.Write(proof.Bsb22Commitments[i].Marshal()) + hashBts = cfg.HashToFieldFn.Sum(hashBts[0:]) + cfg.HashToFieldFn.Reset() + hashedCmt.SetBytes(hashBts[:nbBuf]) // Computing L_{CommitmentIndex} @@ -136,7 +150,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) Mul(&lagrange, &lagrangeOne) // wⁱ/n (ζⁿ-1)/(ζ-wⁱ) - xiLi.Mul(&lagrange, &hashRes[0]) + xiLi.Mul(&lagrange, &hashedCmt) pi.Add(&pi, &xiLi) } } @@ -250,7 +264,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { digestsToFold, &proof.BatchedProof, zeta, - hFunc, + cfg.KZGFoldingHash, zu.Marshal(), ) if err != nil { diff --git a/backend/plonk/bls24-315/prove.go b/backend/plonk/bls24-315/prove.go index 1facb4194d..09f0643a47 100644 --- a/backend/plonk/bls24-315/prove.go +++ b/backend/plonk/bls24-315/prove.go @@ -18,9 +18,8 @@ package plonk import ( "context" - "crypto/sha256" "errors" - "golang.org/x/sync/errgroup" + "fmt" "hash" "math/big" "math/bits" @@ -28,24 +27,25 @@ import ( "sync" "time" - "github.com/consensys/gnark/backend/witness" + "golang.org/x/sync/errgroup" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" - curve "github.com/consensys/gnark-crypto/ecc/bls24-315" - "github.com/consensys/gnark-crypto/ecc/bls24-315/kzg" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fft" - + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/hash_to_field" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/iop" - cs "github.com/consensys/gnark/constraint/bls24-315" - "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark-crypto/ecc/bls24-315/kzg" + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" + cs "github.com/consensys/gnark/constraint/bls24-315" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" @@ -122,14 +122,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // parse the options opt, err := backend.NewProverConfig(opts...) if err != nil { - return nil, err + return nil, fmt.Errorf("get prover options: %w", err) } start := time.Now() // init instance g, ctx := errgroup.WithContext(context.Background()) - instance := newInstance(ctx, spr, pk, fullWitness, &opt) + instance, err := newInstance(ctx, spr, pk, fullWitness, &opt) + if err != nil { + return nil, fmt.Errorf("new instance: %w", err) + } // solve constraints g.Go(instance.solveConstraints) @@ -181,8 +184,9 @@ type instance struct { spr *cs.SparseR1CS opt *backend.ProverConfig - fs fiatshamir.Transcript - hFunc hash.Hash + fs fiatshamir.Transcript + kzgFoldingHash hash.Hash // for KZG folding + htfFunc hash.Hash // hash to field function // polynomials x []*iop.Polynomial // x stores tracks the polynomial we need @@ -223,8 +227,10 @@ type instance struct { chGammaBeta chan struct{} } -func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts *backend.ProverConfig) instance { - hFunc := sha256.New() +func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts *backend.ProverConfig) (*instance, error) { + if opts.HashToFieldFn == nil { + opts.HashToFieldFn = hash_to_field.New([]byte("BSB22-Plonk")) + } s := instance{ ctx: ctx, pk: pk, @@ -233,8 +239,9 @@ func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWi opt: opts, fullWitness: fullWitness, bp: make([]*iop.Polynomial, nb_blinding_polynomials), - fs: fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta"), - hFunc: hFunc, + fs: fiatshamir.NewTranscript(opts.ChallengeHash, "gamma", "beta", "alpha", "zeta"), + kzgFoldingHash: opts.KZGFoldingHash, + htfFunc: opts.HashToFieldFn, chLRO: make(chan struct{}, 1), chQk: make(chan struct{}, 1), chbp: make(chan struct{}, 1), @@ -251,7 +258,7 @@ func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWi s.setupGKRHints() s.x = make([]*iop.Polynomial, id_Qci+2*len(s.commitmentInfo)) - return s + return &s, nil } func (s *instance) initComputeNumerator() error { @@ -309,6 +316,8 @@ func (s *instance) initBSB22Commitments() { // Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg func (s *instance) bsb22Hint(commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { + var err error + res := &s.commitmentVal[commDepth] commitmentInfo := s.spr.CommitmentInfo.(constraint.PlonkCommitments)[commDepth] @@ -317,10 +326,6 @@ func (s *instance) bsb22Hint(commDepth int) solver.Hint { for i := range ins { committedValues[offset+commitmentInfo.Committed[i]].SetBigInt(ins[i]) } - var ( - err error - hashRes []fr.Element - ) if _, err = committedValues[offset+commitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } @@ -333,10 +338,14 @@ func (s *instance) bsb22Hint(commDepth int) solver.Hint { } s.cCommitments[commDepth].ToCanonical(&s.pk.Domain[0]).ToRegular() - if hashRes, err = fr.Hash(s.proof.Bsb22Commitments[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err + s.htfFunc.Write(s.proof.Bsb22Commitments[commDepth].Marshal()) + hashBts := s.htfFunc.Sum(nil) + s.htfFunc.Reset() + nbBuf := fr.Bytes + if s.htfFunc.Size() < fr.Bytes { + nbBuf = s.htfFunc.Size() } - res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + res.SetBytes(hashBts[:nbBuf]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses res.BigInt(outs[0]) return nil @@ -816,7 +825,7 @@ func (s *instance) batchOpening() error { polysToOpen, digestsToOpen, s.zeta, - s.hFunc, + s.kzgFoldingHash, s.pk.Kzg, s.proof.ZShiftedOpening.ClaimedValue.Marshal(), ) diff --git a/backend/plonk/bls24-315/verify.go b/backend/plonk/bls24-315/verify.go index d5120deb41..446c95ff42 100644 --- a/backend/plonk/bls24-315/verify.go +++ b/backend/plonk/bls24-315/verify.go @@ -17,20 +17,24 @@ package plonk import ( - "crypto/sha256" "errors" + "fmt" "io" "math/big" - "time" - "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" + "time" - "github.com/consensys/gnark-crypto/ecc/bls24-315/kzg" + "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls24-315" - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" + + "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/hash_to_field" + + "github.com/consensys/gnark-crypto/ecc/bls24-315/kzg" + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend" "github.com/consensys/gnark/logger" ) @@ -38,19 +42,20 @@ var ( errWrongClaimedQuotient = errors.New("claimed quotient is not as expected") ) -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { log := logger.Logger().With().Str("curve", "bls24-315").Str("backend", "plonk").Logger() start := time.Now() + cfg, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("create backend config: %w", err) + } if len(proof.Bsb22Commitments) != len(vk.Qcp) { return errors.New("BSB22 Commitment number mismatch") } - // pick a hash function to derive the challenge (the same as in the prover) - hFunc := sha256.New() - // transcript to derive the challenge - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta") // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. @@ -119,11 +124,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } } + if cfg.HashToFieldFn == nil { + cfg.HashToFieldFn = hash_to_field.New([]byte("BSB22-Plonk")) + } + var hashBts []byte + var hashedCmt fr.Element + nbBuf := fr.Bytes + if cfg.HashToFieldFn.Size() < fr.Bytes { + nbBuf = cfg.HashToFieldFn.Size() + } for i := range vk.CommitmentConstraintIndexes { - var hashRes []fr.Element - if hashRes, err = fr.Hash(proof.Bsb22Commitments[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err - } + cfg.HashToFieldFn.Write(proof.Bsb22Commitments[i].Marshal()) + hashBts = cfg.HashToFieldFn.Sum(hashBts[0:]) + cfg.HashToFieldFn.Reset() + hashedCmt.SetBytes(hashBts[:nbBuf]) // Computing L_{CommitmentIndex} @@ -136,7 +150,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) Mul(&lagrange, &lagrangeOne) // wⁱ/n (ζⁿ-1)/(ζ-wⁱ) - xiLi.Mul(&lagrange, &hashRes[0]) + xiLi.Mul(&lagrange, &hashedCmt) pi.Add(&pi, &xiLi) } } @@ -250,7 +264,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { digestsToFold, &proof.BatchedProof, zeta, - hFunc, + cfg.KZGFoldingHash, zu.Marshal(), ) if err != nil { diff --git a/backend/plonk/bls24-317/prove.go b/backend/plonk/bls24-317/prove.go index 4565d7edb5..49412d739a 100644 --- a/backend/plonk/bls24-317/prove.go +++ b/backend/plonk/bls24-317/prove.go @@ -18,9 +18,8 @@ package plonk import ( "context" - "crypto/sha256" "errors" - "golang.org/x/sync/errgroup" + "fmt" "hash" "math/big" "math/bits" @@ -28,24 +27,25 @@ import ( "sync" "time" - "github.com/consensys/gnark/backend/witness" + "golang.org/x/sync/errgroup" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" - curve "github.com/consensys/gnark-crypto/ecc/bls24-317" - "github.com/consensys/gnark-crypto/ecc/bls24-317/kzg" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fft" - + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/hash_to_field" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/iop" - cs "github.com/consensys/gnark/constraint/bls24-317" - "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark-crypto/ecc/bls24-317/kzg" + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" + cs "github.com/consensys/gnark/constraint/bls24-317" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" @@ -122,14 +122,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // parse the options opt, err := backend.NewProverConfig(opts...) if err != nil { - return nil, err + return nil, fmt.Errorf("get prover options: %w", err) } start := time.Now() // init instance g, ctx := errgroup.WithContext(context.Background()) - instance := newInstance(ctx, spr, pk, fullWitness, &opt) + instance, err := newInstance(ctx, spr, pk, fullWitness, &opt) + if err != nil { + return nil, fmt.Errorf("new instance: %w", err) + } // solve constraints g.Go(instance.solveConstraints) @@ -181,8 +184,9 @@ type instance struct { spr *cs.SparseR1CS opt *backend.ProverConfig - fs fiatshamir.Transcript - hFunc hash.Hash + fs fiatshamir.Transcript + kzgFoldingHash hash.Hash // for KZG folding + htfFunc hash.Hash // hash to field function // polynomials x []*iop.Polynomial // x stores tracks the polynomial we need @@ -223,8 +227,10 @@ type instance struct { chGammaBeta chan struct{} } -func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts *backend.ProverConfig) instance { - hFunc := sha256.New() +func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts *backend.ProverConfig) (*instance, error) { + if opts.HashToFieldFn == nil { + opts.HashToFieldFn = hash_to_field.New([]byte("BSB22-Plonk")) + } s := instance{ ctx: ctx, pk: pk, @@ -233,8 +239,9 @@ func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWi opt: opts, fullWitness: fullWitness, bp: make([]*iop.Polynomial, nb_blinding_polynomials), - fs: fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta"), - hFunc: hFunc, + fs: fiatshamir.NewTranscript(opts.ChallengeHash, "gamma", "beta", "alpha", "zeta"), + kzgFoldingHash: opts.KZGFoldingHash, + htfFunc: opts.HashToFieldFn, chLRO: make(chan struct{}, 1), chQk: make(chan struct{}, 1), chbp: make(chan struct{}, 1), @@ -251,7 +258,7 @@ func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWi s.setupGKRHints() s.x = make([]*iop.Polynomial, id_Qci+2*len(s.commitmentInfo)) - return s + return &s, nil } func (s *instance) initComputeNumerator() error { @@ -309,6 +316,8 @@ func (s *instance) initBSB22Commitments() { // Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg func (s *instance) bsb22Hint(commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { + var err error + res := &s.commitmentVal[commDepth] commitmentInfo := s.spr.CommitmentInfo.(constraint.PlonkCommitments)[commDepth] @@ -317,10 +326,6 @@ func (s *instance) bsb22Hint(commDepth int) solver.Hint { for i := range ins { committedValues[offset+commitmentInfo.Committed[i]].SetBigInt(ins[i]) } - var ( - err error - hashRes []fr.Element - ) if _, err = committedValues[offset+commitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } @@ -333,10 +338,14 @@ func (s *instance) bsb22Hint(commDepth int) solver.Hint { } s.cCommitments[commDepth].ToCanonical(&s.pk.Domain[0]).ToRegular() - if hashRes, err = fr.Hash(s.proof.Bsb22Commitments[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err + s.htfFunc.Write(s.proof.Bsb22Commitments[commDepth].Marshal()) + hashBts := s.htfFunc.Sum(nil) + s.htfFunc.Reset() + nbBuf := fr.Bytes + if s.htfFunc.Size() < fr.Bytes { + nbBuf = s.htfFunc.Size() } - res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + res.SetBytes(hashBts[:nbBuf]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses res.BigInt(outs[0]) return nil @@ -816,7 +825,7 @@ func (s *instance) batchOpening() error { polysToOpen, digestsToOpen, s.zeta, - s.hFunc, + s.kzgFoldingHash, s.pk.Kzg, s.proof.ZShiftedOpening.ClaimedValue.Marshal(), ) diff --git a/backend/plonk/bls24-317/verify.go b/backend/plonk/bls24-317/verify.go index df12fc0881..ab64624d7c 100644 --- a/backend/plonk/bls24-317/verify.go +++ b/backend/plonk/bls24-317/verify.go @@ -17,20 +17,24 @@ package plonk import ( - "crypto/sha256" "errors" + "fmt" "io" "math/big" - "time" - "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" + "time" - "github.com/consensys/gnark-crypto/ecc/bls24-317/kzg" + "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bls24-317" - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" + + "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/hash_to_field" + + "github.com/consensys/gnark-crypto/ecc/bls24-317/kzg" + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend" "github.com/consensys/gnark/logger" ) @@ -38,19 +42,20 @@ var ( errWrongClaimedQuotient = errors.New("claimed quotient is not as expected") ) -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { log := logger.Logger().With().Str("curve", "bls24-317").Str("backend", "plonk").Logger() start := time.Now() + cfg, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("create backend config: %w", err) + } if len(proof.Bsb22Commitments) != len(vk.Qcp) { return errors.New("BSB22 Commitment number mismatch") } - // pick a hash function to derive the challenge (the same as in the prover) - hFunc := sha256.New() - // transcript to derive the challenge - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta") // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. @@ -119,11 +124,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } } + if cfg.HashToFieldFn == nil { + cfg.HashToFieldFn = hash_to_field.New([]byte("BSB22-Plonk")) + } + var hashBts []byte + var hashedCmt fr.Element + nbBuf := fr.Bytes + if cfg.HashToFieldFn.Size() < fr.Bytes { + nbBuf = cfg.HashToFieldFn.Size() + } for i := range vk.CommitmentConstraintIndexes { - var hashRes []fr.Element - if hashRes, err = fr.Hash(proof.Bsb22Commitments[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err - } + cfg.HashToFieldFn.Write(proof.Bsb22Commitments[i].Marshal()) + hashBts = cfg.HashToFieldFn.Sum(hashBts[0:]) + cfg.HashToFieldFn.Reset() + hashedCmt.SetBytes(hashBts[:nbBuf]) // Computing L_{CommitmentIndex} @@ -136,7 +150,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) Mul(&lagrange, &lagrangeOne) // wⁱ/n (ζⁿ-1)/(ζ-wⁱ) - xiLi.Mul(&lagrange, &hashRes[0]) + xiLi.Mul(&lagrange, &hashedCmt) pi.Add(&pi, &xiLi) } } @@ -250,7 +264,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { digestsToFold, &proof.BatchedProof, zeta, - hFunc, + cfg.KZGFoldingHash, zu.Marshal(), ) if err != nil { diff --git a/backend/plonk/bn254/prove.go b/backend/plonk/bn254/prove.go index 385ddf3aa2..1a237418d6 100644 --- a/backend/plonk/bn254/prove.go +++ b/backend/plonk/bn254/prove.go @@ -18,9 +18,8 @@ package plonk import ( "context" - "crypto/sha256" "errors" - "golang.org/x/sync/errgroup" + "fmt" "hash" "math/big" "math/bits" @@ -28,24 +27,25 @@ import ( "sync" "time" - "github.com/consensys/gnark/backend/witness" + "golang.org/x/sync/errgroup" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bn254/fr" - curve "github.com/consensys/gnark-crypto/ecc/bn254" - "github.com/consensys/gnark-crypto/ecc/bn254/kzg" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/fft" - + "github.com/consensys/gnark-crypto/ecc/bn254/fr/hash_to_field" "github.com/consensys/gnark-crypto/ecc/bn254/fr/iop" - cs "github.com/consensys/gnark/constraint/bn254" - "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark-crypto/ecc/bn254/kzg" + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" + cs "github.com/consensys/gnark/constraint/bn254" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" @@ -122,14 +122,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // parse the options opt, err := backend.NewProverConfig(opts...) if err != nil { - return nil, err + return nil, fmt.Errorf("get prover options: %w", err) } start := time.Now() // init instance g, ctx := errgroup.WithContext(context.Background()) - instance := newInstance(ctx, spr, pk, fullWitness, &opt) + instance, err := newInstance(ctx, spr, pk, fullWitness, &opt) + if err != nil { + return nil, fmt.Errorf("new instance: %w", err) + } // solve constraints g.Go(instance.solveConstraints) @@ -181,8 +184,9 @@ type instance struct { spr *cs.SparseR1CS opt *backend.ProverConfig - fs fiatshamir.Transcript - hFunc hash.Hash + fs fiatshamir.Transcript + kzgFoldingHash hash.Hash // for KZG folding + htfFunc hash.Hash // hash to field function // polynomials x []*iop.Polynomial // x stores tracks the polynomial we need @@ -223,8 +227,10 @@ type instance struct { chGammaBeta chan struct{} } -func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts *backend.ProverConfig) instance { - hFunc := sha256.New() +func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts *backend.ProverConfig) (*instance, error) { + if opts.HashToFieldFn == nil { + opts.HashToFieldFn = hash_to_field.New([]byte("BSB22-Plonk")) + } s := instance{ ctx: ctx, pk: pk, @@ -233,8 +239,9 @@ func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWi opt: opts, fullWitness: fullWitness, bp: make([]*iop.Polynomial, nb_blinding_polynomials), - fs: fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta"), - hFunc: hFunc, + fs: fiatshamir.NewTranscript(opts.ChallengeHash, "gamma", "beta", "alpha", "zeta"), + kzgFoldingHash: opts.KZGFoldingHash, + htfFunc: opts.HashToFieldFn, chLRO: make(chan struct{}, 1), chQk: make(chan struct{}, 1), chbp: make(chan struct{}, 1), @@ -251,7 +258,7 @@ func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWi s.setupGKRHints() s.x = make([]*iop.Polynomial, id_Qci+2*len(s.commitmentInfo)) - return s + return &s, nil } func (s *instance) initComputeNumerator() error { @@ -309,6 +316,8 @@ func (s *instance) initBSB22Commitments() { // Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg func (s *instance) bsb22Hint(commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { + var err error + res := &s.commitmentVal[commDepth] commitmentInfo := s.spr.CommitmentInfo.(constraint.PlonkCommitments)[commDepth] @@ -317,10 +326,6 @@ func (s *instance) bsb22Hint(commDepth int) solver.Hint { for i := range ins { committedValues[offset+commitmentInfo.Committed[i]].SetBigInt(ins[i]) } - var ( - err error - hashRes []fr.Element - ) if _, err = committedValues[offset+commitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } @@ -333,10 +338,14 @@ func (s *instance) bsb22Hint(commDepth int) solver.Hint { } s.cCommitments[commDepth].ToCanonical(&s.pk.Domain[0]).ToRegular() - if hashRes, err = fr.Hash(s.proof.Bsb22Commitments[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err + s.htfFunc.Write(s.proof.Bsb22Commitments[commDepth].Marshal()) + hashBts := s.htfFunc.Sum(nil) + s.htfFunc.Reset() + nbBuf := fr.Bytes + if s.htfFunc.Size() < fr.Bytes { + nbBuf = s.htfFunc.Size() } - res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + res.SetBytes(hashBts[:nbBuf]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses res.BigInt(outs[0]) return nil @@ -816,7 +825,7 @@ func (s *instance) batchOpening() error { polysToOpen, digestsToOpen, s.zeta, - s.hFunc, + s.kzgFoldingHash, s.pk.Kzg, s.proof.ZShiftedOpening.ClaimedValue.Marshal(), ) diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index 08ec69b2f4..1e0d7ca4de 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -17,25 +17,24 @@ package plonk import ( - "crypto/sha256" "errors" + "fmt" "io" "math/big" + "text/template" "time" - "github.com/consensys/gnark-crypto/ecc/bn254/fr" - - "fmt" - "github.com/consensys/gnark-crypto/ecc/bn254/fp" - - "github.com/consensys/gnark-crypto/ecc/bn254/kzg" + "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bn254" - "text/template" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr/hash_to_field" - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark-crypto/ecc/bn254/kzg" + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend" "github.com/consensys/gnark/logger" ) @@ -43,19 +42,20 @@ var ( errWrongClaimedQuotient = errors.New("claimed quotient is not as expected") ) -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { log := logger.Logger().With().Str("curve", "bn254").Str("backend", "plonk").Logger() start := time.Now() + cfg, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("create backend config: %w", err) + } if len(proof.Bsb22Commitments) != len(vk.Qcp) { return errors.New("BSB22 Commitment number mismatch") } - // pick a hash function to derive the challenge (the same as in the prover) - hFunc := sha256.New() - // transcript to derive the challenge - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta") // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. @@ -124,11 +124,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } } + if cfg.HashToFieldFn == nil { + cfg.HashToFieldFn = hash_to_field.New([]byte("BSB22-Plonk")) + } + var hashBts []byte + var hashedCmt fr.Element + nbBuf := fr.Bytes + if cfg.HashToFieldFn.Size() < fr.Bytes { + nbBuf = cfg.HashToFieldFn.Size() + } for i := range vk.CommitmentConstraintIndexes { - var hashRes []fr.Element - if hashRes, err = fr.Hash(proof.Bsb22Commitments[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err - } + cfg.HashToFieldFn.Write(proof.Bsb22Commitments[i].Marshal()) + hashBts = cfg.HashToFieldFn.Sum(hashBts[0:]) + cfg.HashToFieldFn.Reset() + hashedCmt.SetBytes(hashBts[:nbBuf]) // Computing L_{CommitmentIndex} @@ -141,7 +150,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) Mul(&lagrange, &lagrangeOne) // wⁱ/n (ζⁿ-1)/(ζ-wⁱ) - xiLi.Mul(&lagrange, &hashRes[0]) + xiLi.Mul(&lagrange, &hashedCmt) pi.Add(&pi, &xiLi) } } @@ -255,7 +264,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { digestsToFold, &proof.BatchedProof, zeta, - hFunc, + cfg.KZGFoldingHash, zu.Marshal(), ) if err != nil { diff --git a/backend/plonk/bw6-633/prove.go b/backend/plonk/bw6-633/prove.go index deb90f0b3e..77d1a48644 100644 --- a/backend/plonk/bw6-633/prove.go +++ b/backend/plonk/bw6-633/prove.go @@ -18,9 +18,8 @@ package plonk import ( "context" - "crypto/sha256" "errors" - "golang.org/x/sync/errgroup" + "fmt" "hash" "math/big" "math/bits" @@ -28,24 +27,25 @@ import ( "sync" "time" - "github.com/consensys/gnark/backend/witness" + "golang.org/x/sync/errgroup" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" - curve "github.com/consensys/gnark-crypto/ecc/bw6-633" - "github.com/consensys/gnark-crypto/ecc/bw6-633/kzg" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fft" - + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/hash_to_field" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/iop" - cs "github.com/consensys/gnark/constraint/bw6-633" - "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark-crypto/ecc/bw6-633/kzg" + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" + cs "github.com/consensys/gnark/constraint/bw6-633" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" @@ -122,14 +122,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // parse the options opt, err := backend.NewProverConfig(opts...) if err != nil { - return nil, err + return nil, fmt.Errorf("get prover options: %w", err) } start := time.Now() // init instance g, ctx := errgroup.WithContext(context.Background()) - instance := newInstance(ctx, spr, pk, fullWitness, &opt) + instance, err := newInstance(ctx, spr, pk, fullWitness, &opt) + if err != nil { + return nil, fmt.Errorf("new instance: %w", err) + } // solve constraints g.Go(instance.solveConstraints) @@ -181,8 +184,9 @@ type instance struct { spr *cs.SparseR1CS opt *backend.ProverConfig - fs fiatshamir.Transcript - hFunc hash.Hash + fs fiatshamir.Transcript + kzgFoldingHash hash.Hash // for KZG folding + htfFunc hash.Hash // hash to field function // polynomials x []*iop.Polynomial // x stores tracks the polynomial we need @@ -223,8 +227,10 @@ type instance struct { chGammaBeta chan struct{} } -func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts *backend.ProverConfig) instance { - hFunc := sha256.New() +func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts *backend.ProverConfig) (*instance, error) { + if opts.HashToFieldFn == nil { + opts.HashToFieldFn = hash_to_field.New([]byte("BSB22-Plonk")) + } s := instance{ ctx: ctx, pk: pk, @@ -233,8 +239,9 @@ func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWi opt: opts, fullWitness: fullWitness, bp: make([]*iop.Polynomial, nb_blinding_polynomials), - fs: fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta"), - hFunc: hFunc, + fs: fiatshamir.NewTranscript(opts.ChallengeHash, "gamma", "beta", "alpha", "zeta"), + kzgFoldingHash: opts.KZGFoldingHash, + htfFunc: opts.HashToFieldFn, chLRO: make(chan struct{}, 1), chQk: make(chan struct{}, 1), chbp: make(chan struct{}, 1), @@ -251,7 +258,7 @@ func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWi s.setupGKRHints() s.x = make([]*iop.Polynomial, id_Qci+2*len(s.commitmentInfo)) - return s + return &s, nil } func (s *instance) initComputeNumerator() error { @@ -309,6 +316,8 @@ func (s *instance) initBSB22Commitments() { // Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg func (s *instance) bsb22Hint(commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { + var err error + res := &s.commitmentVal[commDepth] commitmentInfo := s.spr.CommitmentInfo.(constraint.PlonkCommitments)[commDepth] @@ -317,10 +326,6 @@ func (s *instance) bsb22Hint(commDepth int) solver.Hint { for i := range ins { committedValues[offset+commitmentInfo.Committed[i]].SetBigInt(ins[i]) } - var ( - err error - hashRes []fr.Element - ) if _, err = committedValues[offset+commitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } @@ -333,10 +338,14 @@ func (s *instance) bsb22Hint(commDepth int) solver.Hint { } s.cCommitments[commDepth].ToCanonical(&s.pk.Domain[0]).ToRegular() - if hashRes, err = fr.Hash(s.proof.Bsb22Commitments[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err + s.htfFunc.Write(s.proof.Bsb22Commitments[commDepth].Marshal()) + hashBts := s.htfFunc.Sum(nil) + s.htfFunc.Reset() + nbBuf := fr.Bytes + if s.htfFunc.Size() < fr.Bytes { + nbBuf = s.htfFunc.Size() } - res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + res.SetBytes(hashBts[:nbBuf]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses res.BigInt(outs[0]) return nil @@ -816,7 +825,7 @@ func (s *instance) batchOpening() error { polysToOpen, digestsToOpen, s.zeta, - s.hFunc, + s.kzgFoldingHash, s.pk.Kzg, s.proof.ZShiftedOpening.ClaimedValue.Marshal(), ) diff --git a/backend/plonk/bw6-633/verify.go b/backend/plonk/bw6-633/verify.go index 5df15baa51..71e7c2cc72 100644 --- a/backend/plonk/bw6-633/verify.go +++ b/backend/plonk/bw6-633/verify.go @@ -17,20 +17,24 @@ package plonk import ( - "crypto/sha256" "errors" + "fmt" "io" "math/big" - "time" - "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" + "time" - "github.com/consensys/gnark-crypto/ecc/bw6-633/kzg" + "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bw6-633" - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" + + "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/hash_to_field" + + "github.com/consensys/gnark-crypto/ecc/bw6-633/kzg" + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend" "github.com/consensys/gnark/logger" ) @@ -38,19 +42,20 @@ var ( errWrongClaimedQuotient = errors.New("claimed quotient is not as expected") ) -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { log := logger.Logger().With().Str("curve", "bw6-633").Str("backend", "plonk").Logger() start := time.Now() + cfg, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("create backend config: %w", err) + } if len(proof.Bsb22Commitments) != len(vk.Qcp) { return errors.New("BSB22 Commitment number mismatch") } - // pick a hash function to derive the challenge (the same as in the prover) - hFunc := sha256.New() - // transcript to derive the challenge - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta") // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. @@ -119,11 +124,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } } + if cfg.HashToFieldFn == nil { + cfg.HashToFieldFn = hash_to_field.New([]byte("BSB22-Plonk")) + } + var hashBts []byte + var hashedCmt fr.Element + nbBuf := fr.Bytes + if cfg.HashToFieldFn.Size() < fr.Bytes { + nbBuf = cfg.HashToFieldFn.Size() + } for i := range vk.CommitmentConstraintIndexes { - var hashRes []fr.Element - if hashRes, err = fr.Hash(proof.Bsb22Commitments[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err - } + cfg.HashToFieldFn.Write(proof.Bsb22Commitments[i].Marshal()) + hashBts = cfg.HashToFieldFn.Sum(hashBts[0:]) + cfg.HashToFieldFn.Reset() + hashedCmt.SetBytes(hashBts[:nbBuf]) // Computing L_{CommitmentIndex} @@ -136,7 +150,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) Mul(&lagrange, &lagrangeOne) // wⁱ/n (ζⁿ-1)/(ζ-wⁱ) - xiLi.Mul(&lagrange, &hashRes[0]) + xiLi.Mul(&lagrange, &hashedCmt) pi.Add(&pi, &xiLi) } } @@ -250,7 +264,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { digestsToFold, &proof.BatchedProof, zeta, - hFunc, + cfg.KZGFoldingHash, zu.Marshal(), ) if err != nil { diff --git a/backend/plonk/bw6-761/prove.go b/backend/plonk/bw6-761/prove.go index e94a9c2981..35d89a6e73 100644 --- a/backend/plonk/bw6-761/prove.go +++ b/backend/plonk/bw6-761/prove.go @@ -18,9 +18,8 @@ package plonk import ( "context" - "crypto/sha256" "errors" - "golang.org/x/sync/errgroup" + "fmt" "hash" "math/big" "math/bits" @@ -28,24 +27,25 @@ import ( "sync" "time" - "github.com/consensys/gnark/backend/witness" + "golang.org/x/sync/errgroup" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" - curve "github.com/consensys/gnark-crypto/ecc/bw6-761" - "github.com/consensys/gnark-crypto/ecc/bw6-761/kzg" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fft" - + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/hash_to_field" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/iop" - cs "github.com/consensys/gnark/constraint/bw6-761" - "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark-crypto/ecc/bw6-761/kzg" + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" + cs "github.com/consensys/gnark/constraint/bw6-761" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/logger" @@ -122,14 +122,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // parse the options opt, err := backend.NewProverConfig(opts...) if err != nil { - return nil, err + return nil, fmt.Errorf("get prover options: %w", err) } start := time.Now() // init instance g, ctx := errgroup.WithContext(context.Background()) - instance := newInstance(ctx, spr, pk, fullWitness, &opt) + instance, err := newInstance(ctx, spr, pk, fullWitness, &opt) + if err != nil { + return nil, fmt.Errorf("new instance: %w", err) + } // solve constraints g.Go(instance.solveConstraints) @@ -181,8 +184,9 @@ type instance struct { spr *cs.SparseR1CS opt *backend.ProverConfig - fs fiatshamir.Transcript - hFunc hash.Hash + fs fiatshamir.Transcript + kzgFoldingHash hash.Hash // for KZG folding + htfFunc hash.Hash // hash to field function // polynomials x []*iop.Polynomial // x stores tracks the polynomial we need @@ -223,8 +227,10 @@ type instance struct { chGammaBeta chan struct{} } -func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts *backend.ProverConfig) instance { - hFunc := sha256.New() +func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts *backend.ProverConfig) (*instance, error) { + if opts.HashToFieldFn == nil { + opts.HashToFieldFn = hash_to_field.New([]byte("BSB22-Plonk")) + } s := instance{ ctx: ctx, pk: pk, @@ -233,8 +239,9 @@ func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWi opt: opts, fullWitness: fullWitness, bp: make([]*iop.Polynomial, nb_blinding_polynomials), - fs: fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta"), - hFunc: hFunc, + fs: fiatshamir.NewTranscript(opts.ChallengeHash, "gamma", "beta", "alpha", "zeta"), + kzgFoldingHash: opts.KZGFoldingHash, + htfFunc: opts.HashToFieldFn, chLRO: make(chan struct{}, 1), chQk: make(chan struct{}, 1), chbp: make(chan struct{}, 1), @@ -251,7 +258,7 @@ func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWi s.setupGKRHints() s.x = make([]*iop.Polynomial, id_Qci+2*len(s.commitmentInfo)) - return s + return &s, nil } func (s *instance) initComputeNumerator() error { @@ -309,6 +316,8 @@ func (s *instance) initBSB22Commitments() { // Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg func (s *instance) bsb22Hint(commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { + var err error + res := &s.commitmentVal[commDepth] commitmentInfo := s.spr.CommitmentInfo.(constraint.PlonkCommitments)[commDepth] @@ -317,10 +326,6 @@ func (s *instance) bsb22Hint(commDepth int) solver.Hint { for i := range ins { committedValues[offset+commitmentInfo.Committed[i]].SetBigInt(ins[i]) } - var ( - err error - hashRes []fr.Element - ) if _, err = committedValues[offset+commitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } @@ -333,10 +338,14 @@ func (s *instance) bsb22Hint(commDepth int) solver.Hint { } s.cCommitments[commDepth].ToCanonical(&s.pk.Domain[0]).ToRegular() - if hashRes, err = fr.Hash(s.proof.Bsb22Commitments[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err + s.htfFunc.Write(s.proof.Bsb22Commitments[commDepth].Marshal()) + hashBts := s.htfFunc.Sum(nil) + s.htfFunc.Reset() + nbBuf := fr.Bytes + if s.htfFunc.Size() < fr.Bytes { + nbBuf = s.htfFunc.Size() } - res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + res.SetBytes(hashBts[:nbBuf]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses res.BigInt(outs[0]) return nil @@ -816,7 +825,7 @@ func (s *instance) batchOpening() error { polysToOpen, digestsToOpen, s.zeta, - s.hFunc, + s.kzgFoldingHash, s.pk.Kzg, s.proof.ZShiftedOpening.ClaimedValue.Marshal(), ) diff --git a/backend/plonk/bw6-761/verify.go b/backend/plonk/bw6-761/verify.go index d9eedf3a1d..e8b4ecd4c6 100644 --- a/backend/plonk/bw6-761/verify.go +++ b/backend/plonk/bw6-761/verify.go @@ -17,20 +17,24 @@ package plonk import ( - "crypto/sha256" "errors" + "fmt" "io" "math/big" - "time" - "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + "time" - "github.com/consensys/gnark-crypto/ecc/bw6-761/kzg" + "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bw6-761" - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/hash_to_field" + + "github.com/consensys/gnark-crypto/ecc/bw6-761/kzg" + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend" "github.com/consensys/gnark/logger" ) @@ -38,19 +42,20 @@ var ( errWrongClaimedQuotient = errors.New("claimed quotient is not as expected") ) -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { log := logger.Logger().With().Str("curve", "bw6-761").Str("backend", "plonk").Logger() start := time.Now() + cfg, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("create backend config: %w", err) + } if len(proof.Bsb22Commitments) != len(vk.Qcp) { return errors.New("BSB22 Commitment number mismatch") } - // pick a hash function to derive the challenge (the same as in the prover) - hFunc := sha256.New() - // transcript to derive the challenge - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta") // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. @@ -119,11 +124,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } } + if cfg.HashToFieldFn == nil { + cfg.HashToFieldFn = hash_to_field.New([]byte("BSB22-Plonk")) + } + var hashBts []byte + var hashedCmt fr.Element + nbBuf := fr.Bytes + if cfg.HashToFieldFn.Size() < fr.Bytes { + nbBuf = cfg.HashToFieldFn.Size() + } for i := range vk.CommitmentConstraintIndexes { - var hashRes []fr.Element - if hashRes, err = fr.Hash(proof.Bsb22Commitments[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err - } + cfg.HashToFieldFn.Write(proof.Bsb22Commitments[i].Marshal()) + hashBts = cfg.HashToFieldFn.Sum(hashBts[0:]) + cfg.HashToFieldFn.Reset() + hashedCmt.SetBytes(hashBts[:nbBuf]) // Computing L_{CommitmentIndex} @@ -136,7 +150,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) Mul(&lagrange, &lagrangeOne) // wⁱ/n (ζⁿ-1)/(ζ-wⁱ) - xiLi.Mul(&lagrange, &hashRes[0]) + xiLi.Mul(&lagrange, &hashedCmt) pi.Add(&pi, &xiLi) } } @@ -250,7 +264,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { digestsToFold, &proof.BatchedProof, zeta, - hFunc, + cfg.KZGFoldingHash, zu.Marshal(), ) if err != nil { diff --git a/backend/plonk/plonk.go b/backend/plonk/plonk.go index 23e05cf6ba..2fd11b18aa 100644 --- a/backend/plonk/plonk.go +++ b/backend/plonk/plonk.go @@ -155,7 +155,7 @@ func Prove(ccs constraint.ConstraintSystem, pk ProvingKey, fullWitness witness.W } // Verify verifies a PLONK proof, from the proof, preprocessed public data, and public witness. -func Verify(proof Proof, vk VerifyingKey, publicWitness witness.Witness) error { +func Verify(proof Proof, vk VerifyingKey, publicWitness witness.Witness, opts ...backend.VerifierOption) error { switch _proof := proof.(type) { @@ -164,49 +164,49 @@ func Verify(proof Proof, vk VerifyingKey, publicWitness witness.Witness) error { if !ok { return witness.ErrInvalidWitness } - return plonk_bn254.Verify(_proof, vk.(*plonk_bn254.VerifyingKey), w) + return plonk_bn254.Verify(_proof, vk.(*plonk_bn254.VerifyingKey), w, opts...) case *plonk_bls12381.Proof: w, ok := publicWitness.Vector().(fr_bls12381.Vector) if !ok { return witness.ErrInvalidWitness } - return plonk_bls12381.Verify(_proof, vk.(*plonk_bls12381.VerifyingKey), w) + return plonk_bls12381.Verify(_proof, vk.(*plonk_bls12381.VerifyingKey), w, opts...) case *plonk_bls12377.Proof: w, ok := publicWitness.Vector().(fr_bls12377.Vector) if !ok { return witness.ErrInvalidWitness } - return plonk_bls12377.Verify(_proof, vk.(*plonk_bls12377.VerifyingKey), w) + return plonk_bls12377.Verify(_proof, vk.(*plonk_bls12377.VerifyingKey), w, opts...) case *plonk_bw6761.Proof: w, ok := publicWitness.Vector().(fr_bw6761.Vector) if !ok { return witness.ErrInvalidWitness } - return plonk_bw6761.Verify(_proof, vk.(*plonk_bw6761.VerifyingKey), w) + return plonk_bw6761.Verify(_proof, vk.(*plonk_bw6761.VerifyingKey), w, opts...) case *plonk_bw6633.Proof: w, ok := publicWitness.Vector().(fr_bw6633.Vector) if !ok { return witness.ErrInvalidWitness } - return plonk_bw6633.Verify(_proof, vk.(*plonk_bw6633.VerifyingKey), w) + return plonk_bw6633.Verify(_proof, vk.(*plonk_bw6633.VerifyingKey), w, opts...) case *plonk_bls24317.Proof: w, ok := publicWitness.Vector().(fr_bls24317.Vector) if !ok { return witness.ErrInvalidWitness } - return plonk_bls24317.Verify(_proof, vk.(*plonk_bls24317.VerifyingKey), w) + return plonk_bls24317.Verify(_proof, vk.(*plonk_bls24317.VerifyingKey), w, opts...) case *plonk_bls24315.Proof: w, ok := publicWitness.Vector().(fr_bls24315.Vector) if !ok { return witness.ErrInvalidWitness } - return plonk_bls24315.Verify(_proof, vk.(*plonk_bls24315.VerifyingKey), w) + return plonk_bls24315.Verify(_proof, vk.(*plonk_bls24315.VerifyingKey), w, opts...) default: panic("unrecognized proof type") diff --git a/backend/plonk/plonk_test.go b/backend/plonk/plonk_test.go index 211ef6a243..3cfe8053b9 100644 --- a/backend/plonk/plonk_test.go +++ b/backend/plonk/plonk_test.go @@ -2,12 +2,14 @@ package plonk_test import ( "bytes" + "fmt" "math/big" "testing" "github.com/consensys/gnark" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/kzg" + "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/plonk" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" @@ -58,6 +60,129 @@ func TestProver(t *testing.T) { } } +func TestCustomHashToField(t *testing.T) { + assert := test.NewAssert(t) + assignment := &commitmentCircuit{X: 1} + for _, curve := range getCurves() { + curve := curve + assert.Run(func(assert *test.Assert) { + ccs, err := frontend.Compile(curve.ScalarField(), scs.NewBuilder, &commitmentCircuit{}) + assert.NoError(err) + srs, err := test.NewKZGSRS(ccs) + assert.NoError(err) + pk, vk, err := plonk.Setup(ccs, srs) + assert.NoError(err) + witness, err := frontend.NewWitness(assignment, curve.ScalarField()) + assert.NoError(err) + assert.Run(func(assert *test.Assert) { + proof, err := plonk.Prove(ccs, pk, witness, backend.WithProverHashToFieldFunction(constantHash{})) + assert.NoError(err) + pubWitness, err := witness.Public() + assert.NoError(err) + err = plonk.Verify(proof, vk, pubWitness, backend.WithVerifierHashToFieldFunction(constantHash{})) + assert.NoError(err) + }, "prover_verifier") + assert.Run(func(assert *test.Assert) { + proof, err := plonk.Prove(ccs, pk, witness, backend.WithProverHashToFieldFunction(constantHash{})) + assert.NoError(err) + pubWitness, err := witness.Public() + assert.NoError(err) + err = plonk.Verify(proof, vk, pubWitness) + assert.Error(err) + }, "prover_only") + assert.Run(func(assert *test.Assert) { + proof, err := plonk.Prove(ccs, pk, witness) + assert.Error(err) + _ = proof + }, "verifier_only") + }, curve.String()) + } +} + +func TestCustomChallengeHash(t *testing.T) { + assert := test.NewAssert(t) + assignment := &smallCircuit{X: 1} + for _, curve := range getCurves() { + curve := curve + assert.Run(func(assert *test.Assert) { + ccs, err := frontend.Compile(curve.ScalarField(), scs.NewBuilder, &smallCircuit{}) + assert.NoError(err) + srs, err := test.NewKZGSRS(ccs) + assert.NoError(err) + pk, vk, err := plonk.Setup(ccs, srs) + assert.NoError(err) + witness, err := frontend.NewWitness(assignment, curve.ScalarField()) + assert.NoError(err) + assert.Run(func(assert *test.Assert) { + proof, err := plonk.Prove(ccs, pk, witness, backend.WithProverChallengeHashFunction(constantHash{})) + assert.NoError(err) + pubWitness, err := witness.Public() + assert.NoError(err) + err = plonk.Verify(proof, vk, pubWitness, backend.WithVerifierChallengeHashFunction(constantHash{})) + assert.NoError(err) + }, "prover_verifier") + assert.Run(func(assert *test.Assert) { + proof, err := plonk.Prove(ccs, pk, witness, backend.WithProverChallengeHashFunction(constantHash{})) + assert.NoError(err) + pubWitness, err := witness.Public() + assert.NoError(err) + err = plonk.Verify(proof, vk, pubWitness) + assert.Error(err) + }, "prover_only") + assert.Run(func(assert *test.Assert) { + proof, err := plonk.Prove(ccs, pk, witness) + assert.NoError(err) + pubWitness, err := witness.Public() + assert.NoError(err) + err = plonk.Verify(proof, vk, pubWitness, backend.WithVerifierChallengeHashFunction(constantHash{})) + assert.Error(err) + }, "verifier_only") + }, curve.String()) + } +} + +func TestCustomKZGFoldingHash(t *testing.T) { + assert := test.NewAssert(t) + assignment := &smallCircuit{X: 1} + for _, curve := range getCurves() { + curve := curve + assert.Run(func(assert *test.Assert) { + ccs, err := frontend.Compile(curve.ScalarField(), scs.NewBuilder, &smallCircuit{}) + assert.NoError(err) + srs, err := test.NewKZGSRS(ccs) + assert.NoError(err) + pk, vk, err := plonk.Setup(ccs, srs) + assert.NoError(err) + witness, err := frontend.NewWitness(assignment, curve.ScalarField()) + assert.NoError(err) + assert.Run(func(assert *test.Assert) { + proof, err := plonk.Prove(ccs, pk, witness, backend.WithProverKZGFoldingHashFunction(constantHash{})) + assert.NoError(err) + pubWitness, err := witness.Public() + assert.NoError(err) + err = plonk.Verify(proof, vk, pubWitness, backend.WithVerifierKZGFoldingHashFunction(constantHash{})) + assert.NoError(err) + }, "prover_verifier") + assert.Run(func(assert *test.Assert) { + proof, err := plonk.Prove(ccs, pk, witness, backend.WithProverKZGFoldingHashFunction(constantHash{})) + assert.NoError(err) + pubWitness, err := witness.Public() + assert.NoError(err) + err = plonk.Verify(proof, vk, pubWitness) + assert.Error(err) + }, "prover_only") + assert.Run(func(assert *test.Assert) { + proof, err := plonk.Prove(ccs, pk, witness) + assert.NoError(err) + pubWitness, err := witness.Public() + assert.NoError(err) + err = plonk.Verify(proof, vk, pubWitness, backend.WithVerifierKZGFoldingHashFunction(constantHash{})) + assert.Error(err) + }, "verifier_only") + }, curve.String()) + } +} + func BenchmarkSetup(b *testing.B) { for _, curve := range getCurves() { b.Run(curve.String(), func(b *testing.B) { @@ -161,6 +286,37 @@ func referenceCircuit(curve ecc.ID) (constraint.ConstraintSystem, frontend.Circu return ccs, &good, srs } +type commitmentCircuit struct { + X frontend.Variable +} + +func (c *commitmentCircuit) Define(api frontend.API) error { + cmt, err := api.(frontend.Committer).Commit(c.X) + if err != nil { + return fmt.Errorf("commit: %w", err) + } + api.AssertIsEqual(cmt, "0xaabbcc") + return nil +} + +type smallCircuit struct { + X frontend.Variable +} + +func (c *smallCircuit) Define(api frontend.API) error { + res := api.Mul(c.X, c.X) + api.AssertIsEqual(c.X, res) + return nil +} + +type constantHash struct{} + +func (h constantHash) Write(p []byte) (n int, err error) { return len(p), nil } +func (h constantHash) Sum(b []byte) []byte { return []byte{0xaa, 0xbb, 0xcc} } +func (h constantHash) Reset() {} +func (h constantHash) Size() int { return 3 } +func (h constantHash) BlockSize() int { return 32 } + func getCurves() []ecc.ID { if testing.Short() { return []ecc.ID{ecc.BN254} diff --git a/backend/plonkfri/bls12-377/prove.go b/backend/plonkfri/bls12-377/prove.go index 97d6c0301e..c0b800e45f 100644 --- a/backend/plonkfri/bls12-377/prove.go +++ b/backend/plonkfri/bls12-377/prove.go @@ -17,7 +17,6 @@ package plonkfri import ( - "crypto/sha256" "math/big" "math/bits" "runtime" @@ -76,11 +75,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts var proof Proof - // pick a hash function that will be used to derive the challenges - hFunc := sha256.New() - // 0 - Fiat Shamir - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(opt.ChallengeHash, "gamma", "beta", "alpha", "zeta") // 1 - solve the system _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) diff --git a/backend/plonkfri/bls12-377/verify.go b/backend/plonkfri/bls12-377/verify.go index b2d6630b07..f4b2653f2f 100644 --- a/backend/plonkfri/bls12-377/verify.go +++ b/backend/plonkfri/bls12-377/verify.go @@ -17,22 +17,25 @@ package plonkfri import ( - "crypto/sha256" "errors" + "fmt" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/fri" - "math/big" - fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend" + "math/big" ) var ErrInvalidAlgebraicRelation = errors.New("algebraic relation does not hold") -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { + cfg, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("create backend config: %w", err) + } // 0 - derive the challenges with Fiat Shamir - hFunc := sha256.New() - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta") dataFiatShamir := make([][fr.Bytes]byte, len(publicWitness)+3) for i := 0; i < len(publicWitness); i++ { diff --git a/backend/plonkfri/bls12-381/prove.go b/backend/plonkfri/bls12-381/prove.go index d121b59a37..aae8121d9f 100644 --- a/backend/plonkfri/bls12-381/prove.go +++ b/backend/plonkfri/bls12-381/prove.go @@ -17,7 +17,6 @@ package plonkfri import ( - "crypto/sha256" "math/big" "math/bits" "runtime" @@ -76,11 +75,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts var proof Proof - // pick a hash function that will be used to derive the challenges - hFunc := sha256.New() - // 0 - Fiat Shamir - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(opt.ChallengeHash, "gamma", "beta", "alpha", "zeta") // 1 - solve the system _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) diff --git a/backend/plonkfri/bls12-381/verify.go b/backend/plonkfri/bls12-381/verify.go index 67c4b4923e..49a1f5bc02 100644 --- a/backend/plonkfri/bls12-381/verify.go +++ b/backend/plonkfri/bls12-381/verify.go @@ -17,22 +17,25 @@ package plonkfri import ( - "crypto/sha256" "errors" + "fmt" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/fri" - "math/big" - fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend" + "math/big" ) var ErrInvalidAlgebraicRelation = errors.New("algebraic relation does not hold") -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { + cfg, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("create backend config: %w", err) + } // 0 - derive the challenges with Fiat Shamir - hFunc := sha256.New() - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta") dataFiatShamir := make([][fr.Bytes]byte, len(publicWitness)+3) for i := 0; i < len(publicWitness); i++ { diff --git a/backend/plonkfri/bls24-315/prove.go b/backend/plonkfri/bls24-315/prove.go index cb1f43fcee..594df2cdc0 100644 --- a/backend/plonkfri/bls24-315/prove.go +++ b/backend/plonkfri/bls24-315/prove.go @@ -17,7 +17,6 @@ package plonkfri import ( - "crypto/sha256" "math/big" "math/bits" "runtime" @@ -76,11 +75,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts var proof Proof - // pick a hash function that will be used to derive the challenges - hFunc := sha256.New() - // 0 - Fiat Shamir - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(opt.ChallengeHash, "gamma", "beta", "alpha", "zeta") // 1 - solve the system _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) diff --git a/backend/plonkfri/bls24-315/verify.go b/backend/plonkfri/bls24-315/verify.go index 81d6c7f36f..ad04736683 100644 --- a/backend/plonkfri/bls24-315/verify.go +++ b/backend/plonkfri/bls24-315/verify.go @@ -17,22 +17,25 @@ package plonkfri import ( - "crypto/sha256" "errors" + "fmt" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" "github.com/consensys/gnark-crypto/ecc/bls24-315/fr/fri" - "math/big" - fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend" + "math/big" ) var ErrInvalidAlgebraicRelation = errors.New("algebraic relation does not hold") -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { + cfg, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("create backend config: %w", err) + } // 0 - derive the challenges with Fiat Shamir - hFunc := sha256.New() - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta") dataFiatShamir := make([][fr.Bytes]byte, len(publicWitness)+3) for i := 0; i < len(publicWitness); i++ { diff --git a/backend/plonkfri/bls24-317/prove.go b/backend/plonkfri/bls24-317/prove.go index 5fc6cbf713..7653db67ae 100644 --- a/backend/plonkfri/bls24-317/prove.go +++ b/backend/plonkfri/bls24-317/prove.go @@ -17,7 +17,6 @@ package plonkfri import ( - "crypto/sha256" "math/big" "math/bits" "runtime" @@ -76,11 +75,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts var proof Proof - // pick a hash function that will be used to derive the challenges - hFunc := sha256.New() - // 0 - Fiat Shamir - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(opt.ChallengeHash, "gamma", "beta", "alpha", "zeta") // 1 - solve the system _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) diff --git a/backend/plonkfri/bls24-317/verify.go b/backend/plonkfri/bls24-317/verify.go index 206b5ae3a1..996302faf5 100644 --- a/backend/plonkfri/bls24-317/verify.go +++ b/backend/plonkfri/bls24-317/verify.go @@ -17,22 +17,25 @@ package plonkfri import ( - "crypto/sha256" "errors" + "fmt" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" "github.com/consensys/gnark-crypto/ecc/bls24-317/fr/fri" - "math/big" - fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend" + "math/big" ) var ErrInvalidAlgebraicRelation = errors.New("algebraic relation does not hold") -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { + cfg, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("create backend config: %w", err) + } // 0 - derive the challenges with Fiat Shamir - hFunc := sha256.New() - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta") dataFiatShamir := make([][fr.Bytes]byte, len(publicWitness)+3) for i := 0; i < len(publicWitness); i++ { diff --git a/backend/plonkfri/bn254/prove.go b/backend/plonkfri/bn254/prove.go index 161ad667f4..4a79841f26 100644 --- a/backend/plonkfri/bn254/prove.go +++ b/backend/plonkfri/bn254/prove.go @@ -17,7 +17,6 @@ package plonkfri import ( - "crypto/sha256" "math/big" "math/bits" "runtime" @@ -76,11 +75,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts var proof Proof - // pick a hash function that will be used to derive the challenges - hFunc := sha256.New() - // 0 - Fiat Shamir - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(opt.ChallengeHash, "gamma", "beta", "alpha", "zeta") // 1 - solve the system _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) diff --git a/backend/plonkfri/bn254/verify.go b/backend/plonkfri/bn254/verify.go index 028c117d69..d28b58ce02 100644 --- a/backend/plonkfri/bn254/verify.go +++ b/backend/plonkfri/bn254/verify.go @@ -17,22 +17,25 @@ package plonkfri import ( - "crypto/sha256" "errors" + "fmt" "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/fr/fri" - "math/big" - fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend" + "math/big" ) var ErrInvalidAlgebraicRelation = errors.New("algebraic relation does not hold") -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { + cfg, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("create backend config: %w", err) + } // 0 - derive the challenges with Fiat Shamir - hFunc := sha256.New() - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta") dataFiatShamir := make([][fr.Bytes]byte, len(publicWitness)+3) for i := 0; i < len(publicWitness); i++ { diff --git a/backend/plonkfri/bw6-633/prove.go b/backend/plonkfri/bw6-633/prove.go index e71df6e7aa..1202013681 100644 --- a/backend/plonkfri/bw6-633/prove.go +++ b/backend/plonkfri/bw6-633/prove.go @@ -17,7 +17,6 @@ package plonkfri import ( - "crypto/sha256" "math/big" "math/bits" "runtime" @@ -76,11 +75,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts var proof Proof - // pick a hash function that will be used to derive the challenges - hFunc := sha256.New() - // 0 - Fiat Shamir - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(opt.ChallengeHash, "gamma", "beta", "alpha", "zeta") // 1 - solve the system _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) diff --git a/backend/plonkfri/bw6-633/verify.go b/backend/plonkfri/bw6-633/verify.go index 491b1ee78a..9b8cd07344 100644 --- a/backend/plonkfri/bw6-633/verify.go +++ b/backend/plonkfri/bw6-633/verify.go @@ -17,22 +17,25 @@ package plonkfri import ( - "crypto/sha256" "errors" + "fmt" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" "github.com/consensys/gnark-crypto/ecc/bw6-633/fr/fri" - "math/big" - fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend" + "math/big" ) var ErrInvalidAlgebraicRelation = errors.New("algebraic relation does not hold") -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { + cfg, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("create backend config: %w", err) + } // 0 - derive the challenges with Fiat Shamir - hFunc := sha256.New() - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta") dataFiatShamir := make([][fr.Bytes]byte, len(publicWitness)+3) for i := 0; i < len(publicWitness); i++ { diff --git a/backend/plonkfri/bw6-761/prove.go b/backend/plonkfri/bw6-761/prove.go index 9092580485..74ccbbc4c5 100644 --- a/backend/plonkfri/bw6-761/prove.go +++ b/backend/plonkfri/bw6-761/prove.go @@ -17,7 +17,6 @@ package plonkfri import ( - "crypto/sha256" "math/big" "math/bits" "runtime" @@ -76,11 +75,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts var proof Proof - // pick a hash function that will be used to derive the challenges - hFunc := sha256.New() - // 0 - Fiat Shamir - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(opt.ChallengeHash, "gamma", "beta", "alpha", "zeta") // 1 - solve the system _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) diff --git a/backend/plonkfri/bw6-761/verify.go b/backend/plonkfri/bw6-761/verify.go index 3e05c16966..458c30b0d3 100644 --- a/backend/plonkfri/bw6-761/verify.go +++ b/backend/plonkfri/bw6-761/verify.go @@ -17,22 +17,25 @@ package plonkfri import ( - "crypto/sha256" "errors" + "fmt" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/fri" - "math/big" - fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend" + "math/big" ) var ErrInvalidAlgebraicRelation = errors.New("algebraic relation does not hold") -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { + cfg, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("create backend config: %w", err) + } // 0 - derive the challenges with Fiat Shamir - hFunc := sha256.New() - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta") dataFiatShamir := make([][fr.Bytes]byte, len(publicWitness)+3) for i := 0; i < len(publicWitness); i++ { diff --git a/backend/plonkfri/plonkfri.go b/backend/plonkfri/plonkfri.go index 5fcb3760eb..6d8df14ecc 100644 --- a/backend/plonkfri/plonkfri.go +++ b/backend/plonkfri/plonkfri.go @@ -133,7 +133,7 @@ func Prove(ccs constraint.ConstraintSystem, pk ProvingKey, fullWitness witness.W } // Verify verifies a PLONK proof, from the proof, preprocessed public data, and public witness. -func Verify(proof Proof, vk VerifyingKey, publicWitness witness.Witness) error { +func Verify(proof Proof, vk VerifyingKey, publicWitness witness.Witness, opts ...backend.VerifierOption) error { switch _proof := proof.(type) { @@ -142,48 +142,48 @@ func Verify(proof Proof, vk VerifyingKey, publicWitness witness.Witness) error { if !ok { return witness.ErrInvalidWitness } - return plonk_bn254.Verify(_proof, vk.(*plonk_bn254.VerifyingKey), w) + return plonk_bn254.Verify(_proof, vk.(*plonk_bn254.VerifyingKey), w, opts...) case *plonk_bls12381.Proof: w, ok := publicWitness.Vector().(fr_bls12381.Vector) if !ok { return witness.ErrInvalidWitness } - return plonk_bls12381.Verify(_proof, vk.(*plonk_bls12381.VerifyingKey), w) + return plonk_bls12381.Verify(_proof, vk.(*plonk_bls12381.VerifyingKey), w, opts...) case *plonk_bls12377.Proof: w, ok := publicWitness.Vector().(fr_bls12377.Vector) if !ok { return witness.ErrInvalidWitness } - return plonk_bls12377.Verify(_proof, vk.(*plonk_bls12377.VerifyingKey), w) + return plonk_bls12377.Verify(_proof, vk.(*plonk_bls12377.VerifyingKey), w, opts...) case *plonk_bw6761.Proof: w, ok := publicWitness.Vector().(fr_bw6761.Vector) if !ok { return witness.ErrInvalidWitness } - return plonk_bw6761.Verify(_proof, vk.(*plonk_bw6761.VerifyingKey), w) + return plonk_bw6761.Verify(_proof, vk.(*plonk_bw6761.VerifyingKey), w, opts...) case *plonk_bw6633.Proof: w, ok := publicWitness.Vector().(fr_bw6633.Vector) if !ok { return witness.ErrInvalidWitness } - return plonk_bw6633.Verify(_proof, vk.(*plonk_bw6633.VerifyingKey), w) + return plonk_bw6633.Verify(_proof, vk.(*plonk_bw6633.VerifyingKey), w, opts...) case *plonk_bls24315.Proof: w, ok := publicWitness.Vector().(fr_bls24315.Vector) if !ok { return witness.ErrInvalidWitness } - return plonk_bls24315.Verify(_proof, vk.(*plonk_bls24315.VerifyingKey), w) + return plonk_bls24315.Verify(_proof, vk.(*plonk_bls24315.VerifyingKey), w, opts...) case *plonk_bls24317.Proof: w, ok := publicWitness.Vector().(fr_bls24317.Vector) if !ok { return witness.ErrInvalidWitness } - return plonk_bls24317.Verify(_proof, vk.(*plonk_bls24317.VerifyingKey), w) + return plonk_bls24317.Verify(_proof, vk.(*plonk_bls24317.VerifyingKey), w, opts...) default: panic("unrecognized proof type") diff --git a/go.mod b/go.mod index 28c4e209fb..4b20076f83 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/bits-and-blooms/bitset v1.8.0 github.com/blang/semver/v4 v4.0.0 github.com/consensys/bavard v0.1.13 - github.com/consensys/gnark-crypto v0.12.2-0.20231017134050-6652a8b98254 + github.com/consensys/gnark-crypto v0.12.2-0.20231020130238-7e44877e07c5 github.com/fxamacker/cbor/v2 v2.5.0 github.com/google/go-cmp v0.5.9 github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b diff --git a/go.sum b/go.sum index cfb98a25a5..11b66eb973 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.12.2-0.20231017134050-6652a8b98254 h1:21iGClQpXhJ0PA6lRBpRbpmJFtfdV7R9QMCsQJ3A9mA= -github.com/consensys/gnark-crypto v0.12.2-0.20231017134050-6652a8b98254/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= +github.com/consensys/gnark-crypto v0.12.2-0.20231020130238-7e44877e07c5 h1:Ud0E+vD8mIknsNJAut+yn/QMKp5mkT06z+sLHKezMQU= +github.com/consensys/gnark-crypto v0.12.2-0.20231020130238-7e44877e07c5/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= diff --git a/internal/generator/backend/main.go b/internal/generator/backend/main.go index cddd33357c..3af25e7b3d 100644 --- a/internal/generator/backend/main.go +++ b/internal/generator/backend/main.go @@ -161,7 +161,6 @@ func main() { {File: filepath.Join(groth16Dir, "verify.go"), Templates: []string{"groth16/groth16.verify.go.tmpl", importCurve}}, {File: filepath.Join(groth16Dir, "prove.go"), Templates: []string{"groth16/groth16.prove.go.tmpl", importCurve}}, {File: filepath.Join(groth16Dir, "setup.go"), Templates: []string{"groth16/groth16.setup.go.tmpl", importCurve}}, - {File: filepath.Join(groth16Dir, "commitment.go"), Templates: []string{"groth16/groth16.commitment.go.tmpl", importCurve}}, {File: filepath.Join(groth16Dir, "marshal.go"), Templates: []string{"groth16/groth16.marshal.go.tmpl", importCurve}}, {File: filepath.Join(groth16Dir, "marshal_test.go"), Templates: []string{"groth16/tests/groth16.marshal.go.tmpl", importCurve}}, } diff --git a/internal/generator/backend/template/imports.go.tmpl b/internal/generator/backend/template/imports.go.tmpl index 2c640e8b34..5ed4441632 100644 --- a/internal/generator/backend/template/imports.go.tmpl +++ b/internal/generator/backend/template/imports.go.tmpl @@ -60,4 +60,8 @@ {{- define "import_gkr"}} "github.com/consensys/gnark-crypto/ecc/{{ toLower .Curve }}/fr/gkr" +{{- end}} + +{{- define "import_hash_to_field" }} + "github.com/consensys/gnark-crypto/ecc/{{ toLower .Curve}}/fr/hash_to_field" {{- end}} \ No newline at end of file diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.commitment.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.commitment.go.tmpl deleted file mode 100644 index aec745a7d6..0000000000 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.commitment.go.tmpl +++ /dev/null @@ -1,11 +0,0 @@ -import ( - {{- template "import_fr" . }} - {{- template "import_curve" . }} - "github.com/consensys/gnark/constraint" - "math/big" -) - -func solveCommitmentWire(commitment *curve.G1Affine, publicCommitted []*big.Int) (fr.Element, error) { - res, err := fr.Hash(constraint.SerializeCommitment(commitment.Marshal(), publicCommitted, (fr.Bits-1)/8+1), []byte(constraint.CommitmentDst), 1) - return res[0], err -} \ No newline at end of file diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl index fa72568220..a495057267 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.prove.go.tmpl @@ -1,12 +1,15 @@ import ( + "fmt" + "runtime" + "math/big" + "time" + {{- template "import_fr" . }} {{- template "import_curve" . }} {{- template "import_backend_cs" . }} {{- template "import_fft" . }} + {{- template "import_hash_to_field" . }} {{- template "import_pedersen" .}} - "runtime" - "math/big" - "time" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/internal/utils" @@ -42,7 +45,10 @@ func (proof *Proof) CurveID() ecc.ID { func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...backend.ProverOption) (*Proof, error) { opt, err := backend.NewProverConfig(opts...) if err != nil { - return nil, err + return nil, fmt.Errorf("new prover config: %w", err) + } + if opt.HashToFieldFn == nil { + opt.HashToFieldFn = hash_to_field.New([]byte(constraint.CommitmentDst)) } log := logger.Logger().With().Str("curve", r1cs.CurveID().String()).Int("nbConstraints", r1cs.GetNbConstraints()).Str("backend", "groth16").Logger() @@ -69,8 +75,15 @@ func Prove(r1cs *cs.R1CS, pk *ProvingKey, fullWitness witness.Witness, opts ...b return err } + opt.HashToFieldFn.Write(constraint.SerializeCommitment(proof.Commitments[i].Marshal(), hashed, (fr.Bits-1)/8+1)) + hashBts := opt.HashToFieldFn.Sum(nil) + opt.HashToFieldFn.Reset() + nbBuf := fr.Bytes + if opt.HashToFieldFn.Size() < fr.Bytes { + nbBuf = opt.HashToFieldFn.Size() + } var res fr.Element - res, err = solveCommitmentWire(&proof.Commitments[i], hashed) + res.SetBytes(hashBts[:nbBuf]) res.BigInt(out[0]) return err } diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl index 04408d09f3..80891eb4a3 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl @@ -1,17 +1,19 @@ import ( - "github.com/consensys/gnark-crypto/ecc" - {{- template "import_curve" . }} - {{- template "import_fr" . }} - "fmt" "errors" - "time" + "fmt" "io" - {{- if eq .Curve "BN254"}} "text/template" {{- end}} + "time" + + "github.com/consensys/gnark-crypto/ecc" + {{- template "import_curve" . }} + {{- template "import_fr" . }} {{- template "import_pedersen" .}} + {{- template "import_hash_to_field" . }} "github.com/consensys/gnark-crypto/utils" + "github.com/consensys/gnark/backend" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/logger" ) @@ -22,7 +24,14 @@ var ( ) // Verify verifies a proof with given VerifyingKey and publicWitness -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { + opt, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("new verifier config: %w", err) + } + if opt.HashToFieldFn == nil { + opt.HashToFieldFn = hash_to_field.New([]byte(constraint.CommitmentDst)) + } nbPublicVars := len(vk.G1.K) - len(vk.PublicAndCommitmentCommitted) @@ -61,12 +70,17 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { copy(commitmentPrehashSerialized[offset:], publicWitness[vk.PublicAndCommitmentCommitted[i][j]-1].Marshal()) offset += fr.Bytes } - if res, err := fr.Hash(commitmentPrehashSerialized[:offset], []byte(constraint.CommitmentDst), 1); err != nil { - return err - } else { - publicWitness = append(publicWitness, res[0]) - copy(commitmentsSerialized[i*fr.Bytes:], res[0].Marshal()) + opt.HashToFieldFn.Write(commitmentPrehashSerialized[:offset]) + hashBts := opt.HashToFieldFn.Sum(nil) + opt.HashToFieldFn.Reset() + nbBuf := fr.Bytes + if opt.HashToFieldFn.Size() < fr.Bytes { + nbBuf = opt.HashToFieldFn.Size() } + var res fr.Element + res.SetBytes(hashBts[:nbBuf]) + publicWitness = append(publicWitness, res) + copy(commitmentsSerialized[i*fr.Bytes:], res.Marshal()) } if folded, err := pedersen.FoldCommitments(proof.Commitments, commitmentsSerialized); err != nil { diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl index 9edee5d06d..7ac814c65d 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.prove.go.tmpl @@ -1,31 +1,31 @@ import ( - "crypto/sha256" + "context" + "errors" + "fmt" + "hash" "math/big" "math/bits" "runtime" - "time" - "errors" "sync" - "hash" - "context" + "time" + "golang.org/x/sync/errgroup" - "github.com/consensys/gnark/backend/witness" - "github.com/consensys/gnark-crypto/ecc" - {{ template "import_fr" . }} {{ template "import_curve" . }} - {{ template "import_kzg" . }} + {{ template "import_fr" . }} {{ template "import_fft" . }} - {{ template "import_backend_cs" . }} + {{- template "import_hash_to_field" . }} "github.com/consensys/gnark-crypto/ecc/{{toLower .Curve}}/fr/iop" - + {{ template "import_kzg" . }} + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/witness" + {{ template "import_backend_cs" . }} + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/constraint/solver" "github.com/consensys/gnark/internal/utils" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/logger" - "github.com/consensys/gnark-crypto/fiat-shamir" - "github.com/consensys/gnark/constraint" ) // TODO in gnark-crypto: @@ -99,14 +99,17 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts // parse the options opt, err := backend.NewProverConfig(opts...) if err != nil { - return nil, err + return nil, fmt.Errorf("get prover options: %w", err) } start := time.Now() // init instance g, ctx := errgroup.WithContext(context.Background()) - instance := newInstance(ctx, spr, pk, fullWitness, &opt) + instance, err := newInstance(ctx, spr, pk, fullWitness, &opt) + if err != nil { + return nil, fmt.Errorf("new instance: %w", err) + } // solve constraints g.Go(instance.solveConstraints) @@ -158,8 +161,9 @@ type instance struct { spr *cs.SparseR1CS opt *backend.ProverConfig - fs fiatshamir.Transcript - hFunc hash.Hash + fs fiatshamir.Transcript + kzgFoldingHash hash.Hash // for KZG folding + htfFunc hash.Hash // hash to field function // polynomials x []*iop.Polynomial // x stores tracks the polynomial we need @@ -200,8 +204,10 @@ type instance struct { chGammaBeta chan struct{} } -func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts *backend.ProverConfig) instance { - hFunc := sha256.New() +func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts *backend.ProverConfig) (*instance, error) { + if opts.HashToFieldFn == nil { + opts.HashToFieldFn = hash_to_field.New([]byte("BSB22-Plonk")) + } s := instance{ ctx: ctx, pk: pk, @@ -210,8 +216,9 @@ func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWi opt: opts, fullWitness: fullWitness, bp: make([]*iop.Polynomial, nb_blinding_polynomials), - fs: fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta"), - hFunc: hFunc, + fs: fiatshamir.NewTranscript(opts.ChallengeHash, "gamma", "beta", "alpha", "zeta"), + kzgFoldingHash: opts.KZGFoldingHash, + htfFunc: opts.HashToFieldFn, chLRO: make(chan struct{}, 1), chQk: make(chan struct{}, 1), chbp: make(chan struct{}, 1), @@ -228,7 +235,7 @@ func newInstance(ctx context.Context, spr *cs.SparseR1CS, pk *ProvingKey, fullWi s.setupGKRHints() s.x = make([]*iop.Polynomial, id_Qci+2*len(s.commitmentInfo)) - return s + return &s, nil } func (s *instance) initComputeNumerator() error { @@ -287,6 +294,8 @@ func (s *instance) initBSB22Commitments() { // Computing and verifying Bsb22 multi-commits explained in https://hackmd.io/x8KsadW3RRyX7YTCFJIkHg func (s *instance) bsb22Hint(commDepth int) solver.Hint { return func(_ *big.Int, ins, outs []*big.Int) error { + var err error + res := &s.commitmentVal[commDepth] commitmentInfo := s.spr.CommitmentInfo.(constraint.PlonkCommitments)[commDepth] @@ -295,10 +304,6 @@ func (s *instance) bsb22Hint(commDepth int) solver.Hint { for i := range ins { committedValues[offset+commitmentInfo.Committed[i]].SetBigInt(ins[i]) } - var ( - err error - hashRes []fr.Element - ) if _, err = committedValues[offset+commitmentInfo.CommitmentIndex].SetRandom(); err != nil { // Commitment injection constraint has qcp = 0. Safe to use for blinding. return err } @@ -311,10 +316,14 @@ func (s *instance) bsb22Hint(commDepth int) solver.Hint { } s.cCommitments[commDepth].ToCanonical(&s.pk.Domain[0]).ToRegular() - if hashRes, err = fr.Hash(s.proof.Bsb22Commitments[commDepth].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err + s.htfFunc.Write(s.proof.Bsb22Commitments[commDepth].Marshal()) + hashBts := s.htfFunc.Sum(nil) + s.htfFunc.Reset() + nbBuf := fr.Bytes + if s.htfFunc.Size() < fr.Bytes { + nbBuf = s.htfFunc.Size() } - res.Set(&hashRes[0]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses + res.SetBytes(hashBts[:nbBuf]) // TODO @Tabaie use CommitmentIndex for this; create a new variable CommitmentConstraintIndex for other uses res.BigInt(outs[0]) return nil @@ -794,7 +803,7 @@ func (s *instance) batchOpening() error { polysToOpen, digestsToOpen, s.zeta, - s.hFunc, + s.kzgFoldingHash, s.pk.Kzg, s.proof.ZShiftedOpening.ClaimedValue.Marshal(), ) diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl index 701ad7997b..04fa61b042 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl @@ -1,41 +1,45 @@ import ( - "crypto/sha256" "errors" + "fmt" + "io" "math/big" + {{ if eq .Curve "BN254" -}} + "text/template" + {{- end }} "time" - "io" + + "github.com/consensys/gnark-crypto/ecc" + {{ template "import_curve" . }} {{ template "import_fr" . }} - {{if eq .Curve "BN254"}} + {{ if eq .Curve "BN254" -}} "github.com/consensys/gnark-crypto/ecc/bn254/fp" - "fmt" - {{end}} + {{- end }} + {{- template "import_hash_to_field" . }} {{ template "import_kzg" . }} - {{ template "import_curve" . }} - {{if eq .Curve "BN254"}} - "text/template" - {{end}} + fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" + "github.com/consensys/gnark/backend" "github.com/consensys/gnark/logger" - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/fiat-shamir" ) var ( errWrongClaimedQuotient = errors.New("claimed quotient is not as expected") ) -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { log := logger.Logger().With().Str("curve", "{{ toLower .Curve }}").Str("backend", "plonk").Logger() start := time.Now() + cfg, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("create backend config: %w", err) + } if len(proof.Bsb22Commitments) != len(vk.Qcp) { return errors.New("BSB22 Commitment number mismatch") } - // pick a hash function to derive the challenge (the same as in the prover) - hFunc := sha256.New() // transcript to derive the challenge - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta") // The first challenge is derived using the public data: the commitments to the permutation, // the coefficients of the circuit, and the public inputs. @@ -104,11 +108,20 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { } } + if cfg.HashToFieldFn == nil { + cfg.HashToFieldFn = hash_to_field.New([]byte("BSB22-Plonk")) + } + var hashBts []byte + var hashedCmt fr.Element + nbBuf := fr.Bytes + if cfg.HashToFieldFn.Size() < fr.Bytes { + nbBuf = cfg.HashToFieldFn.Size() + } for i := range vk.CommitmentConstraintIndexes { - var hashRes []fr.Element - if hashRes, err = fr.Hash(proof.Bsb22Commitments[i].Marshal(), []byte("BSB22-Plonk"), 1); err != nil { - return err - } + cfg.HashToFieldFn.Write(proof.Bsb22Commitments[i].Marshal()) + hashBts = cfg.HashToFieldFn.Sum(hashBts[0:]) + cfg.HashToFieldFn.Reset() + hashedCmt.SetBytes(hashBts[:nbBuf]) // Computing L_{CommitmentIndex} @@ -121,7 +134,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) Mul(&lagrange, &lagrangeOne) // wⁱ/n (ζⁿ-1)/(ζ-wⁱ) - xiLi.Mul(&lagrange, &hashRes[0]) + xiLi.Mul(&lagrange, &hashedCmt) pi.Add(&pi, &xiLi) } } @@ -235,7 +248,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { digestsToFold, &proof.BatchedProof, zeta, - hFunc, + cfg.KZGFoldingHash, zu.Marshal(), ) if err != nil { diff --git a/internal/generator/backend/template/zkpschemes/plonkfri/plonk.prove.go.tmpl b/internal/generator/backend/template/zkpschemes/plonkfri/plonk.prove.go.tmpl index 5f3ee2ccf2..d8f50bee1d 100644 --- a/internal/generator/backend/template/zkpschemes/plonkfri/plonk.prove.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonkfri/plonk.prove.go.tmpl @@ -1,5 +1,4 @@ import ( - "crypto/sha256" "math/big" "math/bits" "runtime" @@ -55,11 +54,8 @@ func Prove(spr *cs.SparseR1CS, pk *ProvingKey, fullWitness witness.Witness, opts var proof Proof - // pick a hash function that will be used to derive the challenges - hFunc := sha256.New() - // 0 - Fiat Shamir - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(opt.ChallengeHash, "gamma", "beta", "alpha", "zeta") // 1 - solve the system _solution, err := spr.Solve(fullWitness, opt.SolverOpts...) diff --git a/internal/generator/backend/template/zkpschemes/plonkfri/plonk.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/plonkfri/plonk.verify.go.tmpl index 26cb1eff25..e033680eac 100644 --- a/internal/generator/backend/template/zkpschemes/plonkfri/plonk.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonkfri/plonk.verify.go.tmpl @@ -1,21 +1,24 @@ import ( - "crypto/sha256" + "fmt" "errors" "math/big" {{- template "import_fri" . }} {{- template "import_fr" . }} - + "github.com/consensys/gnark/backend" fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" ) var ErrInvalidAlgebraicRelation = errors.New("algebraic relation does not hold") -func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector) error { +func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...backend.VerifierOption) error { + cfg, err := backend.NewVerifierConfig(opts...) + if err != nil { + return fmt.Errorf("create backend config: %w", err) + } // 0 - derive the challenges with Fiat Shamir - hFunc := sha256.New() - fs := fiatshamir.NewTranscript(hFunc, "gamma", "beta", "alpha", "zeta") + fs := fiatshamir.NewTranscript(cfg.ChallengeHash, "gamma", "beta", "alpha", "zeta") dataFiatShamir := make([][fr.Bytes]byte, len(publicWitness)+3) for i := 0; i < len(publicWitness); i++ { diff --git a/test/assert_checkcircuit.go b/test/assert_checkcircuit.go index f3d215adba..3ae327c886 100644 --- a/test/assert_checkcircuit.go +++ b/test/assert_checkcircuit.go @@ -125,7 +125,7 @@ func (assert *Assert) CheckCircuit(circuit frontend.Circuit, opts ...TestingOpti proof, err := concreteBackend.prove(ccs, pk, w.full, opt.proverOpts...) assert.noError(err, &w) - err = concreteBackend.verify(proof, vk, w.public) + err = concreteBackend.verify(proof, vk, w.public, opt.verifierOpts...) assert.noError(err, &w) if checkSolidity { @@ -225,7 +225,7 @@ type fnSetup func(ccs constraint.ConstraintSystem, curve ecc.ID) ( pkBuilder, vkBuilder, proofBuilder func() any, err error) type fnProve func(ccs constraint.ConstraintSystem, pk any, fullWitness witness.Witness, opts ...backend.ProverOption) (proof any, err error) -type fnVerify func(proof, vk any, publicWitness witness.Witness) error +type fnVerify func(proof, vk any, publicWitness witness.Witness, opts ...backend.VerifierOption) error // tBackend abstracts the backend implementation in the test package. type tBackend struct { @@ -246,8 +246,8 @@ var ( prove: func(ccs constraint.ConstraintSystem, pk any, fullWitness witness.Witness, opts ...backend.ProverOption) (proof any, err error) { return groth16.Prove(ccs, pk.(groth16.ProvingKey), fullWitness, opts...) }, - verify: func(proof, vk any, publicWitness witness.Witness) error { - return groth16.Verify(proof.(groth16.Proof), vk.(groth16.VerifyingKey), publicWitness) + verify: func(proof, vk any, publicWitness witness.Witness, opts ...backend.VerifierOption) error { + return groth16.Verify(proof.(groth16.Proof), vk.(groth16.VerifyingKey), publicWitness, opts...) }, } @@ -266,8 +266,8 @@ var ( prove: func(ccs constraint.ConstraintSystem, pk any, fullWitness witness.Witness, opts ...backend.ProverOption) (proof any, err error) { return plonk.Prove(ccs, pk.(plonk.ProvingKey), fullWitness, opts...) }, - verify: func(proof, vk any, publicWitness witness.Witness) error { - return plonk.Verify(proof.(plonk.Proof), vk.(plonk.VerifyingKey), publicWitness) + verify: func(proof, vk any, publicWitness witness.Witness, opts ...backend.VerifierOption) error { + return plonk.Verify(proof.(plonk.Proof), vk.(plonk.VerifyingKey), publicWitness, opts...) }, } @@ -282,8 +282,8 @@ var ( prove: func(ccs constraint.ConstraintSystem, pk any, fullWitness witness.Witness, opts ...backend.ProverOption) (proof any, err error) { return plonkfri.Prove(ccs, pk.(plonkfri.ProvingKey), fullWitness, opts...) }, - verify: func(proof, vk any, publicWitness witness.Witness) error { - return plonkfri.Verify(proof, vk.(plonkfri.VerifyingKey), publicWitness) + verify: func(proof, vk any, publicWitness witness.Witness, opts ...backend.VerifierOption) error { + return plonkfri.Verify(proof, vk.(plonkfri.VerifyingKey), publicWitness, opts...) }, } ) diff --git a/test/assert_options.go b/test/assert_options.go index 6cbd8d4341..31d0226183 100644 --- a/test/assert_options.go +++ b/test/assert_options.go @@ -16,9 +16,10 @@ type TestingOption func(*testingConfig) error type testingConfig struct { profile - solverOpts []solver.Option - proverOpts []backend.ProverOption - compileOpts []frontend.CompileOption + solverOpts []solver.Option + proverOpts []backend.ProverOption + verifierOpts []backend.VerifierOption + compileOpts []frontend.CompileOption validAssignments []frontend.Circuit invalidAssignments []frontend.Circuit @@ -166,3 +167,12 @@ func WithCompileOpts(compileOpts ...frontend.CompileOption) TestingOption { return nil } } + +// WithVerifierOpts is a testing option which uses the given verifierOpts when +// calling backend.Verify method. +func WithVerifierOpts(verifierOpts ...backend.VerifierOption) TestingOption { + return func(tc *testingConfig) error { + tc.verifierOpts = append(tc.verifierOpts, verifierOpts...) + return nil + } +}