From 53fee2d4ed667e287c580a8c976e2b622bb46ad0 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 3 Nov 2023 13:17:43 +0100 Subject: [PATCH 01/27] test: add recursion hash tests --- std/recursion/wrapped_hash_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/std/recursion/wrapped_hash_test.go b/std/recursion/wrapped_hash_test.go index 66f4737455..6f2e662cad 100644 --- a/std/recursion/wrapped_hash_test.go +++ b/std/recursion/wrapped_hash_test.go @@ -215,6 +215,21 @@ func TestHashMarshalScalar(t *testing.T) { } assert.CheckCircuit(circuit, test.WithCurves(ecc.BW6_761), test.WithValidAssignment(assignment), test.NoFuzzing(), test.NoSerializationChecks(), test.NoSolidityChecks(), test.NoProverChecks()) }) + assert.Run(func(assert *test.Assert) { + var s fr_bls24315.Element + s.SetRandom() + h, err := recursion.NewShort(ecc.BW6_633.ScalarField(), ecc.BLS24_315.ScalarField()) + assert.NoError(err) + marshalled := s.Marshal() + h.Write(marshalled) + hashed := h.Sum(nil) + circuit := &hashMarshalScalarCircuit[sw_bls24315.ScalarField, sw_bls24315.G1Affine]{} + assignment := &hashMarshalScalarCircuit[sw_bls24315.ScalarField, sw_bls24315.G1Affine]{ + Scalar: sw_bls24315.NewScalar(s), + Expected: hashed, + } + assert.CheckCircuit(circuit, test.WithCurves(ecc.BW6_633), test.WithValidAssignment(assignment), test.NoFuzzing(), test.NoSerializationChecks(), test.NoSolidityChecks(), test.NoProverChecks()) + }) } type transcriptCircuit[FR emulated.FieldParams, G1El algebra.G1ElementT] struct { From e29589cd6f87bc5c03c4192b582c37a74e94a2f5 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Mon, 20 Nov 2023 13:32:53 +0100 Subject: [PATCH 02/27] fix: accumulate MSM result --- std/algebra/emulated/sw_emulated/point.go | 2 +- std/algebra/native/sw_bls12377/pairing2.go | 2 +- std/algebra/native/sw_bls24315/pairing2.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/std/algebra/emulated/sw_emulated/point.go b/std/algebra/emulated/sw_emulated/point.go index 404b6fc5c6..c8467a479d 100644 --- a/std/algebra/emulated/sw_emulated/point.go +++ b/std/algebra/emulated/sw_emulated/point.go @@ -647,7 +647,7 @@ func (c *Curve[B, S]) MultiScalarMul(p []*AffinePoint[B], s []*emulated.Element[ res := c.ScalarMul(p[0], s[0]) for i := 1; i < len(p); i++ { q := c.ScalarMul(p[i], s[i]) - c.AddUnified(res, q) + res = c.AddUnified(res, q) } return res, nil } diff --git a/std/algebra/native/sw_bls12377/pairing2.go b/std/algebra/native/sw_bls12377/pairing2.go index 63d8b1d614..9dad86475a 100644 --- a/std/algebra/native/sw_bls12377/pairing2.go +++ b/std/algebra/native/sw_bls12377/pairing2.go @@ -126,7 +126,7 @@ func (c *Curve) MultiScalarMul(P []*G1Affine, scalars []*Scalar) (*G1Affine, err res := c.ScalarMul(P[0], scalars[0]) for i := 1; i < len(P); i++ { q := c.ScalarMul(P[i], scalars[i]) - c.Add(res, q) + res = c.Add(res, q) } return res, nil } diff --git a/std/algebra/native/sw_bls24315/pairing2.go b/std/algebra/native/sw_bls24315/pairing2.go index 21441f926d..f61216c3fc 100644 --- a/std/algebra/native/sw_bls24315/pairing2.go +++ b/std/algebra/native/sw_bls24315/pairing2.go @@ -126,7 +126,7 @@ func (c *Curve) MultiScalarMul(P []*G1Affine, scalars []*Scalar) (*G1Affine, err res := c.ScalarMul(P[0], scalars[0]) for i := 1; i < len(P); i++ { q := c.ScalarMul(P[i], scalars[i]) - c.Add(res, q) + res = c.Add(res, q) } return res, nil } From 395a6d76f31e4b785abc78d96dba6af1dcff23d4 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Mon, 20 Nov 2023 13:33:51 +0100 Subject: [PATCH 03/27] refactor: take emulated element for additional data --- std/commitments/kzg/verifier.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/std/commitments/kzg/verifier.go b/std/commitments/kzg/verifier.go index 3b077a6354..353fab8846 100644 --- a/std/commitments/kzg/verifier.go +++ b/std/commitments/kzg/verifier.go @@ -364,7 +364,7 @@ func (v *Verifier[FR, G1El, G2El, GTEl]) CheckOpeningProof(commitment Commitment return nil } -func (v *Verifier[FR, G1El, G2El, GTEl]) BatchVerifySinglePoint(digests []Commitment[G1El], batchOpeningProof BatchOpeningProof[FR, G1El], point emulated.Element[FR], vk VerifyingKey[G1El, G2El], dataTranscript ...frontend.Variable) error { +func (v *Verifier[FR, G1El, G2El, GTEl]) BatchVerifySinglePoint(digests []Commitment[G1El], batchOpeningProof BatchOpeningProof[FR, G1El], point emulated.Element[FR], vk VerifyingKey[G1El, G2El], dataTranscript ...emulated.Element[FR]) error { // fold the proof foldedProof, foldedDigest, err := v.FoldProof(digests, batchOpeningProof, point, dataTranscript...) if err != nil { @@ -489,7 +489,7 @@ func (v *Verifier[FR, G1El, G2El, GTEl]) BatchVerifyMultiPoints(digests []Commit return err } -func (v *Verifier[FR, G1El, G2El, GTEl]) FoldProof(digests []Commitment[G1El], batchOpeningProof BatchOpeningProof[FR, G1El], point emulated.Element[FR], dataTranscript ...frontend.Variable) (OpeningProof[FR, G1El], Commitment[G1El], error) { +func (v *Verifier[FR, G1El, G2El, GTEl]) FoldProof(digests []Commitment[G1El], batchOpeningProof BatchOpeningProof[FR, G1El], point emulated.Element[FR], dataTranscript ...emulated.Element[FR]) (OpeningProof[FR, G1El], Commitment[G1El], error) { var retP OpeningProof[FR, G1El] var retC Commitment[G1El] nbDigests := len(digests) @@ -525,7 +525,7 @@ func (v *Verifier[FR, G1El, G2El, GTEl]) FoldProof(digests []Commitment[G1El], b // deriveGamma derives a challenge using Fiat Shamir to fold proofs. // dataTranscript are supposed to be bits. -func (v *Verifier[FR, G1El, G2El, GTEl]) deriveGamma(point emulated.Element[FR], digests []Commitment[G1El], claimedValues []emulated.Element[FR], dataTranscript ...frontend.Variable) (*emulated.Element[FR], error) { +func (v *Verifier[FR, G1El, G2El, GTEl]) deriveGamma(point emulated.Element[FR], digests []Commitment[G1El], claimedValues []emulated.Element[FR], dataTranscript ...emulated.Element[FR]) (*emulated.Element[FR], error) { var fr FR fs, err := recursion.NewTranscript(v.api, fr.Modulus(), []string{"gamma"}) if err != nil { @@ -546,8 +546,10 @@ func (v *Verifier[FR, G1El, G2El, GTEl]) deriveGamma(point emulated.Element[FR], } } - if err := fs.Bind("gamma", dataTranscript); err != nil { - return nil, fmt.Errorf("bind data transcript: %w", err) + for i := range dataTranscript { + if err := fs.Bind("gamma", v.curve.MarshalScalar(dataTranscript[i])); err != nil { + return nil, fmt.Errorf("bind %d-ith data transcript: %w", i, err) + } } gamma, err := fs.ComputeChallenge("gamma") From 3945e902b8c2ba6d66bbf9dba10cef9f460f8466 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Fri, 10 Nov 2023 12:31:38 +0100 Subject: [PATCH 04/27] fix: handled infinity point in native multi scalar exp --- std/algebra/native/sw_bls12377/pairing2.go | 7 ++++++- std/algebra/native/sw_bls24315/pairing2.go | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/std/algebra/native/sw_bls12377/pairing2.go b/std/algebra/native/sw_bls12377/pairing2.go index 9dad86475a..a8971a3641 100644 --- a/std/algebra/native/sw_bls12377/pairing2.go +++ b/std/algebra/native/sw_bls12377/pairing2.go @@ -126,7 +126,12 @@ func (c *Curve) MultiScalarMul(P []*G1Affine, scalars []*Scalar) (*G1Affine, err res := c.ScalarMul(P[0], scalars[0]) for i := 1; i < len(P); i++ { q := c.ScalarMul(P[i], scalars[i]) - res = c.Add(res, q) + + // check for infinity + isInfinity := c.api.And(c.api.IsZero(P[i].X), c.api.IsZero(P[i].Y)) + tmp := c.Add(res, q) + res.X = c.api.Select(isInfinity, res.X, tmp.X) + res.Y = c.api.Select(isInfinity, res.Y, tmp.Y) } return res, nil } diff --git a/std/algebra/native/sw_bls24315/pairing2.go b/std/algebra/native/sw_bls24315/pairing2.go index f61216c3fc..c75baedc81 100644 --- a/std/algebra/native/sw_bls24315/pairing2.go +++ b/std/algebra/native/sw_bls24315/pairing2.go @@ -126,7 +126,12 @@ func (c *Curve) MultiScalarMul(P []*G1Affine, scalars []*Scalar) (*G1Affine, err res := c.ScalarMul(P[0], scalars[0]) for i := 1; i < len(P); i++ { q := c.ScalarMul(P[i], scalars[i]) - res = c.Add(res, q) + + // check for infinity... + isInfinity := c.api.And(c.api.IsZero(P[i].X), c.api.IsZero(P[i].Y)) + tmp := c.Add(res, q) + res.X = c.api.Select(isInfinity, res.X, tmp.X) + res.Y = c.api.Select(isInfinity, res.Y, tmp.Y) } return res, nil } From daae22c94d8a513332a36ce05afc95475a461e55 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Mon, 20 Nov 2023 13:49:33 +0100 Subject: [PATCH 05/27] fix: use only nbBits when creating scalar --- std/commitments/kzg/verifier.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/std/commitments/kzg/verifier.go b/std/commitments/kzg/verifier.go index 353fab8846..d284a87be8 100644 --- a/std/commitments/kzg/verifier.go +++ b/std/commitments/kzg/verifier.go @@ -36,6 +36,7 @@ import ( "github.com/consensys/gnark/std/algebra/emulated/sw_bw6761" "github.com/consensys/gnark/std/algebra/native/sw_bls12377" "github.com/consensys/gnark/std/algebra/native/sw_bls24315" + "github.com/consensys/gnark/std/math/bits" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/std/recursion" ) @@ -418,7 +419,7 @@ func (v *Verifier[FR, G1El, G2El, GTEl]) BatchVerifyMultiPoints(digests []Commit } seed := whSnark.Sum() - binSeed := v.api.ToBinary(seed) + binSeed := bits.ToBinary(v.api, seed, bits.WithNbDigits(fr.Modulus().BitLen())) randomNumbers[1] = v.scalarApi.FromBits(binSeed...) for i := 2; i < len(randomNumbers); i++ { @@ -556,7 +557,7 @@ func (v *Verifier[FR, G1El, G2El, GTEl]) deriveGamma(point emulated.Element[FR], if err != nil { return nil, fmt.Errorf("compute challenge: %w", err) } - bGamma := v.api.ToBinary(gamma) + bGamma := bits.ToBinary(v.api, gamma, bits.WithNbDigits(fr.Modulus().BitLen())) gammaS := v.scalarApi.FromBits(bGamma...) return gammaS, nil From 7a41420cbf566469a0c3dfed7dec7e923fe70b94 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Mon, 20 Nov 2023 13:47:20 +0100 Subject: [PATCH 06/27] feat: add PLONK verifier --- std/recursion/plonk/verifier.go | 629 +++++++++++++++++++++++++++ std/recursion/plonk/verifier_test.go | 121 ++++++ 2 files changed, 750 insertions(+) create mode 100644 std/recursion/plonk/verifier.go create mode 100644 std/recursion/plonk/verifier_test.go diff --git a/std/recursion/plonk/verifier.go b/std/recursion/plonk/verifier.go new file mode 100644 index 0000000000..40ed430a94 --- /dev/null +++ b/std/recursion/plonk/verifier.go @@ -0,0 +1,629 @@ +package plonk + +import ( + "fmt" + stdbits "math/bits" + + fr_bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + fr_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + fr_bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" + fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" + backend_plonk "github.com/consensys/gnark/backend/plonk" + plonkbackend_bls12377 "github.com/consensys/gnark/backend/plonk/bls12-377" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/algebra" + "github.com/consensys/gnark/std/algebra/emulated/sw_bls12381" + "github.com/consensys/gnark/std/algebra/emulated/sw_bn254" + "github.com/consensys/gnark/std/algebra/native/sw_bls12377" + "github.com/consensys/gnark/std/algebra/native/sw_bls24315" + "github.com/consensys/gnark/std/commitments/kzg" + fiatshamir "github.com/consensys/gnark/std/fiat-shamir" + "github.com/consensys/gnark/std/math/bits" + "github.com/consensys/gnark/std/math/emulated" + "github.com/consensys/gnark/std/recursion" +) + +type Proof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT] struct { + // Commitments to the solution vectors + LRO [3]kzg.Commitment[G1El] + // Commitment to Z, the permutation polynomial + Z kzg.Commitment[G1El] + // Commitments to h1, h2, h3 such that h = h1 + Xh2 + X**2h3 is the quotient polynomial + H [3]kzg.Commitment[G1El] + + Bsb22Commitments []kzg.Commitment[G1El] + + // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime + BatchedProof kzg.BatchOpeningProof[FR, G1El] + + // Opening proof of Z at zeta*mu + ZShiftedOpening kzg.OpeningProof[FR, G1El] +} + +func ValueOfProof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT](proof backend_plonk.Proof) (Proof[FR, G1El, G2El], error) { + var ret Proof[FR, G1El, G2El] + var err error + switch r := any(&ret).(type) { + case *Proof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine]: + tProof, ok := proof.(*plonkbackend_bls12377.Proof) + if !ok { + return ret, fmt.Errorf("expected sw_bls12377.Proof, got %T", proof) + } + for i := range r.LRO { + r.LRO[i], err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tProof.LRO[i]) + if err != nil { + return ret, fmt.Errorf("commitment LRO[%d] value assignment: %w", i, err) + } + } + r.Z, err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tProof.Z) + if err != nil { + return ret, fmt.Errorf("commitment Z value assignment: %w", err) + } + for i := range r.H { + r.H[i], err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tProof.H[i]) + if err != nil { + return ret, fmt.Errorf("commitment H[%d] value assignment: %w", i, err) + } + } + r.Bsb22Commitments = make([]kzg.Commitment[sw_bls12377.G1Affine], len(tProof.Bsb22Commitments)) + for i := range r.Bsb22Commitments { + r.Bsb22Commitments[i], err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tProof.Bsb22Commitments[i]) + if err != nil { + return ret, fmt.Errorf("bsb22 commitment %d value assignment: %w", i, err) + } + } + // TODO: actually we compute the opening point later. Maybe we can precompute it here and later assert its correctness? + r.BatchedProof, err = kzg.ValueOfBatchOpeningProof[sw_bls12377.ScalarField, sw_bls12377.G1Affine](tProof.BatchedProof) + if err != nil { + return ret, fmt.Errorf("batch opening proof value assignment: %w", err) + } + r.ZShiftedOpening, err = kzg.ValueOfOpeningProof[sw_bls12377.ScalarField, sw_bls12377.G1Affine](tProof.ZShiftedOpening) + if err != nil { + return ret, fmt.Errorf("z shifted opening proof value assignment: %w", err) + } + default: + return ret, fmt.Errorf("unknown parametric type combination: %T", ret) + } + return ret, nil +} + +func PlaceholderProof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT](ccs constraint.ConstraintSystem) Proof[FR, G1El, G2El] { + return Proof[FR, G1El, G2El]{ + BatchedProof: kzg.BatchOpeningProof[FR, G1El]{ + ClaimedValues: make([]emulated.Element[FR], 7), + }, + } +} + +type VerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT] struct { + // Size circuit + Size uint64 + SizeInv emulated.Element[FR] + Generator emulated.Element[FR] + NbPublicVariables uint64 + + // Commitment scheme that is used for an instantiation of PLONK + Kzg kzg.VerifyingKey[G1El, G2El] + + // cosetShift generator of the coset on the small domain + CosetShift emulated.Element[FR] + + // S commitments to S1, S2, S3 + S [3]kzg.Commitment[G1El] + + // Commitments to ql, qr, qm, qo, qcp prepended with as many zeroes (ones for l) as there are public inputs. + // In particular Qk is not complete. + Ql, Qr, Qm, Qo, Qk kzg.Commitment[G1El] + + Qcp []kzg.Commitment[G1El] + + CommitmentConstraintIndexes []uint64 +} + +func ValueOfVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT](vk backend_plonk.VerifyingKey) (VerifyingKey[FR, G1El, G2El], error) { + var ret VerifyingKey[FR, G1El, G2El] + var err error + switch r := any(&ret).(type) { + case *VerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine]: + tVk, ok := vk.(*plonkbackend_bls12377.VerifyingKey) + if !ok { + return ret, fmt.Errorf("expected bls12377.VerifyingKey, got %T", vk) + } + r.Size = tVk.Size + r.SizeInv = sw_bls12377.NewScalar(tVk.SizeInv) + r.Generator = sw_bls12377.NewScalar(tVk.Generator) + r.NbPublicVariables = tVk.NbPublicVariables + r.Kzg, err = kzg.ValueOfVerifyingKey[sw_bls12377.G1Affine, sw_bls12377.G2Affine](tVk.Kzg) + if err != nil { + return ret, fmt.Errorf("verifying key witness assignment: %w", err) + } + r.CosetShift = sw_bls12377.NewScalar(tVk.CosetShift) + for i := range r.S { + r.S[i], err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tVk.S[i]) + if err != nil { + return ret, fmt.Errorf("commitment S[%d] witness assignment: %w", i, err) + } + } + r.Ql, err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tVk.Ql) + if err != nil { + return ret, fmt.Errorf("commitment Ql witness assignment: %w", err) + } + r.Qr, err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tVk.Qr) + if err != nil { + return ret, fmt.Errorf("commitment Qr witness assignment: %w", err) + } + r.Qm, err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tVk.Qm) + if err != nil { + return ret, fmt.Errorf("commitment Qm witness assignment: %w", err) + } + r.Qo, err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tVk.Qo) + if err != nil { + return ret, fmt.Errorf("commitment Qo witness assignment: %w", err) + } + r.Qk, err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tVk.Qk) + if err != nil { + return ret, fmt.Errorf("commitment Qk witness assignment: %w", err) + } + r.Qcp = make([]kzg.Commitment[sw_bls12377.G1Affine], len(tVk.Qcp)) + for i := range r.Qcp { + r.Qcp[i], err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tVk.Qcp[i]) + if err != nil { + return ret, fmt.Errorf("commitment Qcp[%d] witness assignment: %w", i, err) + } + } + r.CommitmentConstraintIndexes = make([]uint64, len(tVk.CommitmentConstraintIndexes)) + copy(r.CommitmentConstraintIndexes, tVk.CommitmentConstraintIndexes) + default: + return ret, fmt.Errorf("unknown parametric type combination") + } + return ret, nil +} + +func PlaceholderVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT](ccs constraint.ConstraintSystem) VerifyingKey[FR, G1El, G2El] { + // TODO: we're not considering the commitments right now + nbPublic := ccs.GetNbPublicVariables() + nbConstraints := ccs.GetNbConstraints() + sizeSystem := nbPublic + nbConstraints + nextPowerTwo := 1 << stdbits.Len(uint(sizeSystem)) + return VerifyingKey[FR, G1El, G2El]{ + Size: uint64(nextPowerTwo), + } +} + +// Witness is a public witness to verify the SNARK proof against. For assigning +// witness use [ValueOfWitness] and to create stub witness for compiling use +// [PlaceholderWitness]. +type Witness[FR emulated.FieldParams] struct { + // Public is the public inputs. The first element does not need to be one + // wire and is added implicitly during verification. + Public []emulated.Element[FR] +} + +func ValueOfWitness[FR emulated.FieldParams](w witness.Witness) (Witness[FR], error) { + var ret Witness[FR] + pubw, err := w.Public() + if err != nil { + return ret, fmt.Errorf("get public witness: %w", err) + } + vec := pubw.Vector() + switch s := any(&ret).(type) { + case *Witness[sw_bn254.ScalarField]: + vect, ok := vec.(fr_bn254.Vector) + if !ok { + return ret, fmt.Errorf("expected fr_bn254.Vector, got %T", vec) + } + for i := range vect { + s.Public = append(s.Public, sw_bn254.NewScalar(vect[i])) + } + case *Witness[sw_bls12377.ScalarField]: + vect, ok := vec.(fr_bls12377.Vector) + if !ok { + return ret, fmt.Errorf("expected fr_bls12377.Vector, got %T", vec) + } + for i := range vect { + s.Public = append(s.Public, sw_bls12377.NewScalar(vect[i])) + } + case *Witness[sw_bls12381.ScalarField]: + vect, ok := vec.(fr_bls12381.Vector) + if !ok { + return ret, fmt.Errorf("expected fr_bls12381.Vector, got %T", vec) + } + for i := range vect { + s.Public = append(s.Public, sw_bls12381.NewScalar(vect[i])) + } + case *Witness[sw_bls24315.ScalarField]: + vect, ok := vec.(fr_bls24315.Vector) + if !ok { + return ret, fmt.Errorf("expected fr_bls24315.Vector, got %T", vec) + } + for i := range vect { + s.Public = append(s.Public, sw_bls24315.NewScalar(vect[i])) + } + default: + return ret, fmt.Errorf("unknown parametric type combination") + } + return ret, nil +} + +// PlaceholderWitness creates a stub witness which can be used to allocate the +// variables in the circuit if the actual witness is not yet known. It takes +// into account the number of public inputs and number of used commitments. +func PlaceholderWitness[FR emulated.FieldParams](ccs constraint.ConstraintSystem) Witness[FR] { + return Witness[FR]{ + Public: make([]emulated.Element[FR], ccs.GetNbPublicVariables()), + } +} + +type Verifier[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT] struct { + api frontend.API + f *emulated.Field[FR] + curve algebra.Curve[FR, G1El] + pairing algebra.Pairing[G1El, G2El, GtEl] + kzg *kzg.Verifier[FR, G1El, G2El, GtEl] +} + +func NewVerifier[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT]( + api frontend.API, curve algebra.Curve[FR, G1El], pairing algebra.Pairing[G1El, G2El, GtEl], +) (*Verifier[FR, G1El, G2El, GtEl], error) { + // var fr FR + f, err := emulated.NewField[FR](api) + if err != nil { + return nil, fmt.Errorf("new scalars: %w", err) + } + kzg, err := kzg.NewVerifier[FR, G1El, G2El, GtEl](api) + if err != nil { + return nil, fmt.Errorf("new kzg verifier: %w", err) + } + return &Verifier[FR, G1El, G2El, GtEl]{ + api: api, + f: f, + curve: curve, + pairing: pairing, + kzg: kzg, + }, nil +} + +func (v *Verifier[FR, G1El, G2El, GtEl]) AssertProof(vk VerifyingKey[FR, G1El, G2El], proof Proof[FR, G1El, G2El], witness Witness[FR]) error { + var fr FR + if len(proof.Bsb22Commitments) != len(vk.Qcp) { + return fmt.Errorf("BSB22 commitment number mismatch") + } + fs, err := recursion.NewTranscript(v.api, fr.Modulus(), []string{"gamma", "beta", "alpha", "zeta"}) + if err != nil { + return fmt.Errorf("init new transcript: %w", err) + } + + if err := v.bindPublicData(fs, "gamma", vk, witness); err != nil { + return fmt.Errorf("bind public data: %w", err) + } + + // The first challenge is derived using the public data: the commitments to the permutation, + // the coefficients of the circuit, and the public inputs. + // derive gamma from the Comm(blinded cl), Comm(blinded cr), Comm(blinded co) + gamma, err := v.deriveRandomness(fs, "gamma", proof.LRO[0].G1El, proof.LRO[1].G1El, proof.LRO[2].G1El) + if err != nil { + return err + } + + // derive beta from Comm(l), Comm(r), Comm(o) + beta, err := v.deriveRandomness(fs, "beta") + if err != nil { + return err + } + + // derive alpha from Comm(l), Comm(r), Comm(o), Com(Z), Bsb22Commitments + alphaDeps := make([]G1El, len(proof.Bsb22Commitments)+1) + for i := range proof.Bsb22Commitments { + alphaDeps[i] = proof.Bsb22Commitments[i].G1El + } + alphaDeps[len(alphaDeps)-1] = proof.Z.G1El + alpha, err := v.deriveRandomness(fs, "alpha", alphaDeps...) + if err != nil { + return err + } + + // derive zeta, the point of evaluation + zeta, err := v.deriveRandomness(fs, "zeta", proof.H[0].G1El, proof.H[1].G1El, proof.H[2].G1El) + if err != nil { + return err + } + + // evaluation of Z=Xⁿ-1 at ζ + one := v.f.One() + zetaPowerM := v.fixedExpN(vk.Size, zeta) // ζⁿ + zzeta := v.f.Sub(zetaPowerM, one) // ζⁿ-1 + + // L1 = (1/n)(ζⁿ-1)/(ζ-1) + denom := v.f.Sub(zeta, one) + lagrangeOne := v.f.Div(zzeta, denom) + lagrangeOne = v.f.Mul(lagrangeOne, &vk.SizeInv) + lagrange := lagrangeOne + // compute PI = ∑_{i Date: Wed, 15 Nov 2023 12:38:05 +0100 Subject: [PATCH 07/27] feat: PlaceholderVerifyingKey takes the vk as argument --- std/recursion/plonk/verifier.go | 74 ++++++++++++++++--- std/recursion/plonk/verifier_test.go | 104 ++++++++++++++++++++++++--- 2 files changed, 162 insertions(+), 16 deletions(-) diff --git a/std/recursion/plonk/verifier.go b/std/recursion/plonk/verifier.go index 40ed430a94..8a35f6b337 100644 --- a/std/recursion/plonk/verifier.go +++ b/std/recursion/plonk/verifier.go @@ -8,8 +8,15 @@ import ( fr_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" fr_bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark/backend/plonk" backend_plonk "github.com/consensys/gnark/backend/plonk" plonkbackend_bls12377 "github.com/consensys/gnark/backend/plonk/bls12-377" + plonkbackend_bls12381 "github.com/consensys/gnark/backend/plonk/bls12-381" + plonkbackend_bls24315 "github.com/consensys/gnark/backend/plonk/bls24-315" + plonkbackend_bls24317 "github.com/consensys/gnark/backend/plonk/bls24-317" + plonkbackend_bn254 "github.com/consensys/gnark/backend/plonk/bn254" + plonkbackend_bw6633 "github.com/consensys/gnark/backend/plonk/bw6-633" + plonkbackend_bw6761 "github.com/consensys/gnark/backend/plonk/bw6-761" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" @@ -26,10 +33,13 @@ import ( ) type Proof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT] struct { + // Commitments to the solution vectors LRO [3]kzg.Commitment[G1El] + // Commitment to Z, the permutation polynomial Z kzg.Commitment[G1El] + // Commitments to h1, h2, h3 such that h = h1 + Xh2 + X**2h3 is the quotient polynomial H [3]kzg.Commitment[G1El] @@ -98,6 +108,7 @@ func PlaceholderProof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El alg } type VerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT] struct { + // Size circuit Size uint64 SizeInv emulated.Element[FR] @@ -181,14 +192,53 @@ func ValueOfVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El return ret, nil } -func PlaceholderVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT](ccs constraint.ConstraintSystem) VerifyingKey[FR, G1El, G2El] { - // TODO: we're not considering the commitments right now - nbPublic := ccs.GetNbPublicVariables() - nbConstraints := ccs.GetNbConstraints() - sizeSystem := nbPublic + nbConstraints - nextPowerTwo := 1 << stdbits.Len(uint(sizeSystem)) - return VerifyingKey[FR, G1El, G2El]{ - Size: uint64(nextPowerTwo), +func PlaceholderVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT](vk plonk.VerifyingKey) VerifyingKey[FR, G1El, G2El] { + + switch tvk := vk.(type) { + case *plonkbackend_bls12377.VerifyingKey: + return VerifyingKey[FR, G1El, G2El]{ + Size: tvk.Size, + NbPublicVariables: tvk.NbPublicVariables, + CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, + } + case *plonkbackend_bn254.VerifyingKey: + return VerifyingKey[FR, G1El, G2El]{ + Size: tvk.Size, + NbPublicVariables: tvk.NbPublicVariables, + CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, + } + case *plonkbackend_bls12381.VerifyingKey: + return VerifyingKey[FR, G1El, G2El]{ + Size: tvk.Size, + NbPublicVariables: tvk.NbPublicVariables, + CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, + } + case *plonkbackend_bw6761.VerifyingKey: + return VerifyingKey[FR, G1El, G2El]{ + Size: tvk.Size, + NbPublicVariables: tvk.NbPublicVariables, + CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, + } + case *plonkbackend_bls24317.VerifyingKey: + return VerifyingKey[FR, G1El, G2El]{ + Size: tvk.Size, + NbPublicVariables: tvk.NbPublicVariables, + CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, + } + case *plonkbackend_bls24315.VerifyingKey: + return VerifyingKey[FR, G1El, G2El]{ + Size: tvk.Size, + NbPublicVariables: tvk.NbPublicVariables, + CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, + } + case *plonkbackend_bw6633.VerifyingKey: + return VerifyingKey[FR, G1El, G2El]{ + Size: tvk.Size, + NbPublicVariables: tvk.NbPublicVariables, + CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, + } + default: + panic("Unrecognised vk") } } @@ -286,10 +336,12 @@ func NewVerifier[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra. } func (v *Verifier[FR, G1El, G2El, GtEl]) AssertProof(vk VerifyingKey[FR, G1El, G2El], proof Proof[FR, G1El, G2El], witness Witness[FR]) error { + var fr FR if len(proof.Bsb22Commitments) != len(vk.Qcp) { return fmt.Errorf("BSB22 commitment number mismatch") } + fs, err := recursion.NewTranscript(v.api, fr.Modulus(), []string{"gamma", "beta", "alpha", "zeta"}) if err != nil { return fmt.Errorf("init new transcript: %w", err) @@ -354,6 +406,7 @@ func (v *Verifier[FR, G1El, G2El, GtEl]) AssertProof(vk VerifyingKey[FR, G1El, G lagrange = v.f.Div(lagrange, denom) } } + // TODO: omitted hashing the commitment constraint indexes // var hashBts []byte @@ -627,3 +680,8 @@ func (v *Verifier[FR, G1El, G2El, GtEl]) fixedExpN(n uint64, s *emulated.Element } return res } + +// computeIthLagrangeAtZeta computes L_{i}(\omega) = \omega^{i}/n (\zeta^{n}-1)/(\zeta-\omega^{i}) +func (v *Verifier[FR, G1El, G2El, GtEl]) computeIthLagrangeAtZeta(i uint64, vf VerifyingKey[FR, G1El, G2El]) { + +} diff --git a/std/recursion/plonk/verifier_test.go b/std/recursion/plonk/verifier_test.go index 7c4abeed3d..cb2d7c24e9 100644 --- a/std/recursion/plonk/verifier_test.go +++ b/std/recursion/plonk/verifier_test.go @@ -19,19 +19,22 @@ import ( "github.com/consensys/gnark/test" ) -type InnerCircuitNative struct { +//----------------------------------------------------------------- +// Without api.Commit + +type InnerCircuitNativeWoCommit struct { P, Q frontend.Variable N frontend.Variable `gnark:",public"` } -func (c *InnerCircuitNative) Define(api frontend.API) error { +func (c *InnerCircuitNativeWoCommit) Define(api frontend.API) error { res := api.Mul(c.P, c.Q) api.AssertIsEqual(res, c.N) return nil } -func getInner(assert *test.Assert, field, outer *big.Int) (constraint.ConstraintSystem, plonk.VerifyingKey, witness.Witness, plonk.Proof) { - innerCcs, err := frontend.Compile(field, scs.NewBuilder, &InnerCircuitNative{}) +func getInnerWoCommit(assert *test.Assert, field, outer *big.Int) (constraint.ConstraintSystem, plonk.VerifyingKey, witness.Witness, plonk.Proof) { + innerCcs, err := frontend.Compile(field, scs.NewBuilder, &InnerCircuitNativeWoCommit{}) assert.NoError(err) srs, err := test.NewKZGSRS(innerCcs) assert.NoError(err) @@ -39,7 +42,7 @@ func getInner(assert *test.Assert, field, outer *big.Int) (constraint.Constraint assert.NoError(err) // inner proof - innerAssignment := &InnerCircuitNative{ + innerAssignment := &InnerCircuitNativeWoCommit{ P: 3, Q: 5, N: 15, @@ -92,9 +95,10 @@ func (c *OuterCircuit[FR, G1El, G2El, GtEl]) Define(api frontend.API) error { return err } -func TestBLS12InBW6(t *testing.T) { +func TestBLS12InBW6WoCommit(t *testing.T) { + assert := test.NewAssert(t) - innerCcs, innerVK, innerWitness, innerProof := getInner(assert, ecc.BLS12_377.ScalarField(), ecc.BW6_761.ScalarField()) + innerCcs, innerVK, innerWitness, innerProof := getInnerWoCommit(assert, ecc.BLS12_377.ScalarField(), ecc.BW6_761.ScalarField()) // outer proof circuitVk, err := ValueOfVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerVK) @@ -107,7 +111,7 @@ func TestBLS12InBW6(t *testing.T) { outerCircuit := &OuterCircuit[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ InnerWitness: PlaceholderWitness[sw_bls12377.ScalarField](innerCcs), Proof: PlaceholderProof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerCcs), - VerifyingKey: PlaceholderVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerCcs), + VerifyingKey: PlaceholderVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerVK), } outerAssignment := &OuterCircuit[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ InnerWitness: circuitWitness, @@ -119,3 +123,87 @@ func TestBLS12InBW6(t *testing.T) { // assert.CheckCircuit(outerCircuit, test.WithValidAssignment(outerAssignment), test.WithCurves(ecc.BW6_761), // test.NoFuzzing(), test.NoSerializationChecks(), test.NoSolidityChecks()) } + +//----------------------------------------------------------------- +// With api.Commit + +type InnerCircuitCommit struct { + P, Q frontend.Variable + N frontend.Variable `gnark:",public"` +} + +func (c *InnerCircuitCommit) Define(api frontend.API) error { + x := api.Mul(c.P, c.P) + y := api.Mul(c.Q, c.Q) + z := api.Add(x, y) + + committer, ok := api.(frontend.Committer) + if !ok { + panic("builder does not implement Commit") + } + u, err := committer.Commit(x, z) + if err != nil { + return err + } + v, err := committer.Commit(c.N) + if err != nil { + return err + } + + api.AssertIsDifferent(u, z) + api.AssertIsDifferent(v, z) + + return nil +} + +func getInnerCommit(assert *test.Assert, field, outer *big.Int) (constraint.ConstraintSystem, plonk.VerifyingKey, witness.Witness, plonk.Proof) { + + innerCcs, err := frontend.Compile(field, scs.NewBuilder, &InnerCircuitNativeWoCommit{}) + assert.NoError(err) + + srs, err := test.NewKZGSRS(innerCcs) + assert.NoError(err) + + innerPK, innerVK, err := plonk.Setup(innerCcs, srs) + assert.NoError(err) + + // inner proof + innerAssignment := &InnerCircuitNativeWoCommit{ + P: 3, + Q: 5, + N: 15, + } + innerWitness, err := frontend.NewWitness(innerAssignment, field) + assert.NoError(err) + fsProverHasher, err := recursion.NewShort(outer, field) + assert.NoError(err) + kzgProverHasher, err := recursion.NewShort(outer, field) + assert.NoError(err) + hashToFieldHasher, err := recursion.NewShort(outer, field) + assert.NoError(err) + innerProof, err := plonk.Prove(innerCcs, innerPK, innerWitness, + backend.WithProverChallengeHashFunction(fsProverHasher), + backend.WithProverKZGFoldingHashFunction(kzgProverHasher), + backend.WithProverHashToFieldFunction(hashToFieldHasher), + ) + assert.NoError(err) + innerPubWitness, err := innerWitness.Public() + assert.NoError(err) + fsVerifierHasher, err := recursion.NewShort(outer, field) + assert.NoError(err) + kzgVerifierHash, err := recursion.NewShort(outer, field) + assert.NoError(err) + err = plonk.Verify(innerProof, innerVK, innerPubWitness, + backend.WithVerifierChallengeHashFunction(fsVerifierHasher), + backend.WithVerifierKZGFoldingHashFunction(kzgVerifierHash), + ) + assert.NoError(err) + return innerCcs, innerVK, innerPubWitness, innerProof +} + +func TestBLS12InBW6Commit(t *testing.T) { + + assert := test.NewAssert(t) + getInnerWoCommit(assert, ecc.BLS12_377.ScalarField(), ecc.BW6_761.ScalarField()) + +} From c72177b3523f4faa64c0284df0ec1e30f6d1cf7c Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Wed, 15 Nov 2023 12:41:38 +0100 Subject: [PATCH 08/27] feat: f -> scalarApi --- std/recursion/plonk/verifier.go | 160 ++++++++++++++++---------------- 1 file changed, 81 insertions(+), 79 deletions(-) diff --git a/std/recursion/plonk/verifier.go b/std/recursion/plonk/verifier.go index 8a35f6b337..a5cb5ec726 100644 --- a/std/recursion/plonk/verifier.go +++ b/std/recursion/plonk/verifier.go @@ -307,11 +307,11 @@ func PlaceholderWitness[FR emulated.FieldParams](ccs constraint.ConstraintSystem } type Verifier[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT] struct { - api frontend.API - f *emulated.Field[FR] - curve algebra.Curve[FR, G1El] - pairing algebra.Pairing[G1El, G2El, GtEl] - kzg *kzg.Verifier[FR, G1El, G2El, GtEl] + api frontend.API + scalarApi *emulated.Field[FR] + curve algebra.Curve[FR, G1El] + pairing algebra.Pairing[G1El, G2El, GtEl] + kzg *kzg.Verifier[FR, G1El, G2El, GtEl] } func NewVerifier[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT]( @@ -327,11 +327,11 @@ func NewVerifier[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra. return nil, fmt.Errorf("new kzg verifier: %w", err) } return &Verifier[FR, G1El, G2El, GtEl]{ - api: api, - f: f, - curve: curve, - pairing: pairing, - kzg: kzg, + api: api, + scalarApi: f, + curve: curve, + pairing: pairing, + kzg: kzg, }, nil } @@ -383,27 +383,27 @@ func (v *Verifier[FR, G1El, G2El, GtEl]) AssertProof(vk VerifyingKey[FR, G1El, G } // evaluation of Z=Xⁿ-1 at ζ - one := v.f.One() - zetaPowerM := v.fixedExpN(vk.Size, zeta) // ζⁿ - zzeta := v.f.Sub(zetaPowerM, one) // ζⁿ-1 + one := v.scalarApi.One() + zetaPowerM := v.fixedExpN(vk.Size, zeta) // ζⁿ + zzeta := v.scalarApi.Sub(zetaPowerM, one) // ζⁿ-1 // L1 = (1/n)(ζⁿ-1)/(ζ-1) - denom := v.f.Sub(zeta, one) - lagrangeOne := v.f.Div(zzeta, denom) - lagrangeOne = v.f.Mul(lagrangeOne, &vk.SizeInv) + denom := v.scalarApi.Sub(zeta, one) + lagrangeOne := v.scalarApi.Div(zzeta, denom) + lagrangeOne = v.scalarApi.Mul(lagrangeOne, &vk.SizeInv) lagrange := lagrangeOne // compute PI = ∑_{i Date: Wed, 15 Nov 2023 15:53:40 +0100 Subject: [PATCH 09/27] feat: addition of computeIthLagrangeAtZeta --- std/recursion/plonk/verifier.go | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/std/recursion/plonk/verifier.go b/std/recursion/plonk/verifier.go index a5cb5ec726..9ac0b19008 100644 --- a/std/recursion/plonk/verifier.go +++ b/std/recursion/plonk/verifier.go @@ -682,8 +682,26 @@ func (v *Verifier[FR, G1El, G2El, GtEl]) fixedExpN(n uint64, s *emulated.Element } // computeIthLagrangeAtZeta computes L_{i}(\omega) = \omega^{i}/n (\zeta^{n}-1)/(\zeta-\omega^{i}) -// func (v *Verifier[FR, G1El, G2El, GtEl]) computeIthLagrangeAtZeta(i uint64, zetaPowerM emulated.Element[FR], vf VerifyingKey[FR, G1El, G2El]) { +func (v *Verifier[FR, G1El, G2El, GtEl]) computeIthLagrangeAtZeta(i uint64, zeta, zetaPowerM emulated.Element[FR], vk VerifyingKey[FR, G1El, G2El]) *emulated.Element[FR] { -// num := v.scalarApi. + one := v.scalarApi.One() + num := v.scalarApi.Sub(&zetaPowerM, one) + + // \omega^{i} + omegai := one + irev := stdbits.Reverse(uint(i)) + for irev != 0 { + omegai = v.scalarApi.Mul(omegai, omegai) + if irev%2 == 1 { + omegai = v.scalarApi.Mul(omegai, &vk.Generator) + } + irev = irev >> 1 + } -// } + den := v.scalarApi.Sub(&zeta, omegai) + + li := v.scalarApi.Div(num, den) + li = v.scalarApi.Mul(li, &vk.SizeInv) + + return li +} From 9595331576b871e4a196488bb6d6e99c3b098648 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Thu, 16 Nov 2023 11:47:47 +0100 Subject: [PATCH 10/27] feat: bsb commitments are added to pi --- std/recursion/plonk/verifier.go | 59 ++++++++++++---------------- std/recursion/plonk/verifier_test.go | 31 +++++++++------ 2 files changed, 46 insertions(+), 44 deletions(-) diff --git a/std/recursion/plonk/verifier.go b/std/recursion/plonk/verifier.go index 9ac0b19008..f37d0bdc1d 100644 --- a/std/recursion/plonk/verifier.go +++ b/std/recursion/plonk/verifier.go @@ -407,38 +407,25 @@ func (v *Verifier[FR, G1El, G2El, GtEl]) AssertProof(vk VerifyingKey[FR, G1El, G } } - // TODO: omitted hashing the commitment constraint indexes - - // 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 { - // cfg.HashToFieldFn.Write(proof.Bsb22Commitments[i].Marshal()) - // hashBts = cfg.HashToFieldFn.Sum(hashBts[0:]) - // cfg.HashToFieldFn.Reset() - // hashedCmt.SetBytes(hashBts[:nbBuf]) - - // // Computing L_{CommitmentIndex} - - // wPowI.Exp(vk.Generator, big.NewInt(int64(vk.NbPublicVariables)+int64(vk.CommitmentConstraintIndexes[i]))) - // den.Sub(&zeta, &wPowI) // ζ-wⁱ - - // lagrange.SetOne(). - // Sub(&zeta, &lagrange). // ζ-1 - // Mul(&lagrange, &wPowI). // wⁱ(ζ-1) - // Div(&lagrange, &den). // wⁱ(ζ-1)/(ζ-wⁱ) - // Mul(&lagrange, &lagrangeOne) // wⁱ/n (ζⁿ-1)/(ζ-wⁱ) - - // xiLi.Mul(&lagrange, &hashedCmt) - // pi.Add(&pi, &xiLi) - // } - // } + if len(vk.CommitmentConstraintIndexes) > 0 { + hashToField, err := recursion.NewHash(v.api, fr.Modulus(), true) + if err != nil { + return err + } + for i := range vk.CommitmentConstraintIndexes { + li := v.computeIthLagrangeAtZeta(vk.CommitmentConstraintIndexes[i], zeta, zetaPowerM, vk) + marshalledCommitment := v.curve.MarshalG1(proof.Bsb22Commitments[i].G1El) + hashToField.Write(marshalledCommitment...) + hashedCmt := hashToField.Sum() + hashedCmtBits := bits.ToBinary(v.api, hashedCmt, bits.WithNbDigits(fr.Modulus().BitLen())) + emulatedHashedCmt := v.scalarApi.FromBits(hashedCmtBits...) + xiLi := v.scalarApi.Mul(emulatedHashedCmt, li) + hashToField.Reset() + pi = v.scalarApi.Add(pi, xiLi) + } + } // linearizedpolynomial + pi(ζ) + α*(Z(μζ))*(l(ζ)+β*s1(ζ)+γ)*(r(ζ)+β*s2(ζ)+γ)*(o(ζ)+γ) - α²*L₁(ζ) - zu := proof.ZShiftedOpening.ClaimedValue claimedQuotient := &proof.BatchedProof.ClaimedValues[0] linearizedPolynomialZeta := &proof.BatchedProof.ClaimedValues[1] @@ -682,14 +669,20 @@ func (v *Verifier[FR, G1El, G2El, GtEl]) fixedExpN(n uint64, s *emulated.Element } // computeIthLagrangeAtZeta computes L_{i}(\omega) = \omega^{i}/n (\zeta^{n}-1)/(\zeta-\omega^{i}) -func (v *Verifier[FR, G1El, G2El, GtEl]) computeIthLagrangeAtZeta(i uint64, zeta, zetaPowerM emulated.Element[FR], vk VerifyingKey[FR, G1El, G2El]) *emulated.Element[FR] { +func (v *Verifier[FR, G1El, G2El, GtEl]) computeIthLagrangeAtZeta(i uint64, zeta, zetaPowerM *emulated.Element[FR], vk VerifyingKey[FR, G1El, G2El]) *emulated.Element[FR] { one := v.scalarApi.One() - num := v.scalarApi.Sub(&zetaPowerM, one) + num := v.scalarApi.Sub(zetaPowerM, one) // \omega^{i} omegai := one irev := stdbits.Reverse(uint(i)) + // skip first zeroes + s := irev % 2 + for s == 0 { + irev = irev >> 1 + s = irev % 2 + } for irev != 0 { omegai = v.scalarApi.Mul(omegai, omegai) if irev%2 == 1 { @@ -698,7 +691,7 @@ func (v *Verifier[FR, G1El, G2El, GtEl]) computeIthLagrangeAtZeta(i uint64, zeta irev = irev >> 1 } - den := v.scalarApi.Sub(&zeta, omegai) + den := v.scalarApi.Sub(zeta, omegai) li := v.scalarApi.Div(num, den) li = v.scalarApi.Mul(li, &vk.SizeInv) diff --git a/std/recursion/plonk/verifier_test.go b/std/recursion/plonk/verifier_test.go index cb2d7c24e9..23fc26f3fb 100644 --- a/std/recursion/plonk/verifier_test.go +++ b/std/recursion/plonk/verifier_test.go @@ -133,6 +133,7 @@ type InnerCircuitCommit struct { } func (c *InnerCircuitCommit) Define(api frontend.API) error { + x := api.Mul(c.P, c.P) y := api.Mul(c.Q, c.Q) z := api.Add(x, y) @@ -145,20 +146,22 @@ func (c *InnerCircuitCommit) Define(api frontend.API) error { if err != nil { return err } - v, err := committer.Commit(c.N) - if err != nil { - return err - } + // v, err := committer.Commit(c.N) + // if err != nil { + // return err + // } + + // api.AssertIsDifferent(v, z) + api.AssertIsDifferent(u, c.N) - api.AssertIsDifferent(u, z) - api.AssertIsDifferent(v, z) + // api.AssertIsDifferent(z, c.N) return nil } func getInnerCommit(assert *test.Assert, field, outer *big.Int) (constraint.ConstraintSystem, plonk.VerifyingKey, witness.Witness, plonk.Proof) { - innerCcs, err := frontend.Compile(field, scs.NewBuilder, &InnerCircuitNativeWoCommit{}) + innerCcs, err := frontend.Compile(field, scs.NewBuilder, &InnerCircuitCommit{}) assert.NoError(err) srs, err := test.NewKZGSRS(innerCcs) @@ -168,7 +171,7 @@ func getInnerCommit(assert *test.Assert, field, outer *big.Int) (constraint.Cons assert.NoError(err) // inner proof - innerAssignment := &InnerCircuitNativeWoCommit{ + innerAssignment := &InnerCircuitCommit{ P: 3, Q: 5, N: 15, @@ -179,13 +182,14 @@ func getInnerCommit(assert *test.Assert, field, outer *big.Int) (constraint.Cons assert.NoError(err) kzgProverHasher, err := recursion.NewShort(outer, field) assert.NoError(err) - hashToFieldHasher, err := recursion.NewShort(outer, field) + htfProverdHasher, err := recursion.NewShort(outer, field) assert.NoError(err) innerProof, err := plonk.Prove(innerCcs, innerPK, innerWitness, backend.WithProverChallengeHashFunction(fsProverHasher), backend.WithProverKZGFoldingHashFunction(kzgProverHasher), - backend.WithProverHashToFieldFunction(hashToFieldHasher), + backend.WithProverHashToFieldFunction(htfProverdHasher), ) + assert.NoError(err) innerPubWitness, err := innerWitness.Public() assert.NoError(err) @@ -193,10 +197,15 @@ func getInnerCommit(assert *test.Assert, field, outer *big.Int) (constraint.Cons assert.NoError(err) kzgVerifierHash, err := recursion.NewShort(outer, field) assert.NoError(err) + htfVerifierHasher, err := recursion.NewShort(outer, field) + assert.NoError(err) err = plonk.Verify(innerProof, innerVK, innerPubWitness, backend.WithVerifierChallengeHashFunction(fsVerifierHasher), backend.WithVerifierKZGFoldingHashFunction(kzgVerifierHash), + backend.WithVerifierHashToFieldFunction(htfVerifierHasher), ) + // backend.WithVerifierChallengeHashFunction(fsProverHasher), + assert.NoError(err) return innerCcs, innerVK, innerPubWitness, innerProof } @@ -204,6 +213,6 @@ func getInnerCommit(assert *test.Assert, field, outer *big.Int) (constraint.Cons func TestBLS12InBW6Commit(t *testing.T) { assert := test.NewAssert(t) - getInnerWoCommit(assert, ecc.BLS12_377.ScalarField(), ecc.BW6_761.ScalarField()) + getInnerCommit(assert, ecc.BLS12_377.ScalarField(), ecc.BW6_761.ScalarField()) } From e958ce63476aa3210d8d8f62cfe4c56811fc6a3f Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Thu, 16 Nov 2023 15:30:11 +0100 Subject: [PATCH 11/27] refactor: PlaceholderProof takes the proof as argument --- std/recursion/plonk/verifier.go | 88 ++++++++++++++++++++++------ std/recursion/plonk/verifier_test.go | 25 +++++++- 2 files changed, 94 insertions(+), 19 deletions(-) diff --git a/std/recursion/plonk/verifier.go b/std/recursion/plonk/verifier.go index f37d0bdc1d..787585b6f0 100644 --- a/std/recursion/plonk/verifier.go +++ b/std/recursion/plonk/verifier.go @@ -8,7 +8,6 @@ import ( fr_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" fr_bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" - "github.com/consensys/gnark/backend/plonk" backend_plonk "github.com/consensys/gnark/backend/plonk" plonkbackend_bls12377 "github.com/consensys/gnark/backend/plonk/bls12-377" plonkbackend_bls12381 "github.com/consensys/gnark/backend/plonk/bls12-381" @@ -99,11 +98,59 @@ func ValueOfProof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra return ret, nil } -func PlaceholderProof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT](ccs constraint.ConstraintSystem) Proof[FR, G1El, G2El] { - return Proof[FR, G1El, G2El]{ - BatchedProof: kzg.BatchOpeningProof[FR, G1El]{ - ClaimedValues: make([]emulated.Element[FR], 7), - }, +func PlaceholderProof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT](proof backend_plonk.Proof) Proof[FR, G1El, G2El] { + switch tproof := proof.(type) { + case *plonkbackend_bls12377.Proof: + return Proof[FR, G1El, G2El]{ + BatchedProof: kzg.BatchOpeningProof[FR, G1El]{ + ClaimedValues: make([]emulated.Element[FR], len(tproof.BatchedProof.ClaimedValues)), + }, + Bsb22Commitments: make([]kzg.Commitment[G1El], len(tproof.Bsb22Commitments)), + } + case *plonkbackend_bn254.Proof: + return Proof[FR, G1El, G2El]{ + BatchedProof: kzg.BatchOpeningProof[FR, G1El]{ + ClaimedValues: make([]emulated.Element[FR], len(tproof.BatchedProof.ClaimedValues)), + }, + Bsb22Commitments: make([]kzg.Commitment[G1El], len(tproof.Bsb22Commitments)), + } + case *plonkbackend_bls12381.Proof: + return Proof[FR, G1El, G2El]{ + BatchedProof: kzg.BatchOpeningProof[FR, G1El]{ + ClaimedValues: make([]emulated.Element[FR], len(tproof.BatchedProof.ClaimedValues)), + }, + Bsb22Commitments: make([]kzg.Commitment[G1El], len(tproof.Bsb22Commitments)), + } + case *plonkbackend_bw6761.Proof: + return Proof[FR, G1El, G2El]{ + BatchedProof: kzg.BatchOpeningProof[FR, G1El]{ + ClaimedValues: make([]emulated.Element[FR], len(tproof.BatchedProof.ClaimedValues)), + }, + Bsb22Commitments: make([]kzg.Commitment[G1El], len(tproof.Bsb22Commitments)), + } + case *plonkbackend_bls24317.Proof: + return Proof[FR, G1El, G2El]{ + BatchedProof: kzg.BatchOpeningProof[FR, G1El]{ + ClaimedValues: make([]emulated.Element[FR], len(tproof.BatchedProof.ClaimedValues)), + }, + Bsb22Commitments: make([]kzg.Commitment[G1El], len(tproof.Bsb22Commitments)), + } + case *plonkbackend_bls24315.Proof: + return Proof[FR, G1El, G2El]{ + BatchedProof: kzg.BatchOpeningProof[FR, G1El]{ + ClaimedValues: make([]emulated.Element[FR], len(tproof.BatchedProof.ClaimedValues)), + }, + Bsb22Commitments: make([]kzg.Commitment[G1El], len(tproof.Bsb22Commitments)), + } + case *plonkbackend_bw6633.Proof: + return Proof[FR, G1El, G2El]{ + BatchedProof: kzg.BatchOpeningProof[FR, G1El]{ + ClaimedValues: make([]emulated.Element[FR], len(tproof.BatchedProof.ClaimedValues)), + }, + Bsb22Commitments: make([]kzg.Commitment[G1El], len(tproof.Bsb22Commitments)), + } + default: + panic("Unrecognised vk") } } @@ -192,7 +239,7 @@ func ValueOfVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El return ret, nil } -func PlaceholderVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT](vk plonk.VerifyingKey) VerifyingKey[FR, G1El, G2El] { +func PlaceholderVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT](vk backend_plonk.VerifyingKey) VerifyingKey[FR, G1El, G2El] { switch tvk := vk.(type) { case *plonkbackend_bls12377.VerifyingKey: @@ -200,42 +247,49 @@ func PlaceholderVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G Size: tvk.Size, NbPublicVariables: tvk.NbPublicVariables, CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, + Qcp: make([]kzg.Commitment[G1El], len(tvk.Qcp)), } case *plonkbackend_bn254.VerifyingKey: return VerifyingKey[FR, G1El, G2El]{ Size: tvk.Size, NbPublicVariables: tvk.NbPublicVariables, CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, + Qcp: make([]kzg.Commitment[G1El], len(tvk.Qcp)), } case *plonkbackend_bls12381.VerifyingKey: return VerifyingKey[FR, G1El, G2El]{ Size: tvk.Size, NbPublicVariables: tvk.NbPublicVariables, CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, + Qcp: make([]kzg.Commitment[G1El], len(tvk.Qcp)), } case *plonkbackend_bw6761.VerifyingKey: return VerifyingKey[FR, G1El, G2El]{ Size: tvk.Size, NbPublicVariables: tvk.NbPublicVariables, CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, + Qcp: make([]kzg.Commitment[G1El], len(tvk.Qcp)), } case *plonkbackend_bls24317.VerifyingKey: return VerifyingKey[FR, G1El, G2El]{ Size: tvk.Size, NbPublicVariables: tvk.NbPublicVariables, CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, + Qcp: make([]kzg.Commitment[G1El], len(tvk.Qcp)), } case *plonkbackend_bls24315.VerifyingKey: return VerifyingKey[FR, G1El, G2El]{ Size: tvk.Size, NbPublicVariables: tvk.NbPublicVariables, CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, + Qcp: make([]kzg.Commitment[G1El], len(tvk.Qcp)), } case *plonkbackend_bw6633.VerifyingKey: return VerifyingKey[FR, G1El, G2El]{ Size: tvk.Size, NbPublicVariables: tvk.NbPublicVariables, CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, + Qcp: make([]kzg.Commitment[G1El], len(tvk.Qcp)), } default: panic("Unrecognised vk") @@ -558,16 +612,15 @@ func (v *Verifier[FR, G1El, G2El, GtEl]) AssertProof(vk VerifyingKey[FR, G1El, G } // Fold the first proof - digestsToFold := []kzg.Commitment[G1El]{ - {G1El: *foldedH}, - {G1El: *linearizedPolynomialDigest}, - proof.LRO[0], - proof.LRO[1], - proof.LRO[2], - vk.S[0], - vk.S[1], - } - digestsToFold = append(digestsToFold, vk.Qcp...) + digestsToFold := make([]kzg.Commitment[G1El], len(vk.Qcp)+7) + copy(digestsToFold[7:], vk.Qcp) + digestsToFold[0] = kzg.Commitment[G1El]{G1El: *foldedH} + digestsToFold[1] = kzg.Commitment[G1El]{G1El: *linearizedPolynomialDigest} + digestsToFold[2] = proof.LRO[0] + digestsToFold[3] = proof.LRO[1] + digestsToFold[4] = proof.LRO[2] + digestsToFold[5] = vk.S[0] + digestsToFold[6] = vk.S[1] foldedProof, foldedDigest, err := v.kzg.FoldProof( digestsToFold, proof.BatchedProof, @@ -600,6 +653,7 @@ func (v *Verifier[FR, G1El, G2El, GtEl]) AssertProof(vk VerifyingKey[FR, G1El, G } func (v *Verifier[FR, G1El, G2El, GtEl]) bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey[FR, G1El, G2El], witness Witness[FR]) error { + // permutation if err := fs.Bind(challenge, v.curve.MarshalG1(vk.S[0].G1El)); err != nil { return err diff --git a/std/recursion/plonk/verifier_test.go b/std/recursion/plonk/verifier_test.go index 23fc26f3fb..d6a8e93cbc 100644 --- a/std/recursion/plonk/verifier_test.go +++ b/std/recursion/plonk/verifier_test.go @@ -110,7 +110,7 @@ func TestBLS12InBW6WoCommit(t *testing.T) { outerCircuit := &OuterCircuit[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ InnerWitness: PlaceholderWitness[sw_bls12377.ScalarField](innerCcs), - Proof: PlaceholderProof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerCcs), + Proof: PlaceholderProof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerProof), VerifyingKey: PlaceholderVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerVK), } outerAssignment := &OuterCircuit[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ @@ -213,6 +213,27 @@ func getInnerCommit(assert *test.Assert, field, outer *big.Int) (constraint.Cons func TestBLS12InBW6Commit(t *testing.T) { assert := test.NewAssert(t) - getInnerCommit(assert, ecc.BLS12_377.ScalarField(), ecc.BW6_761.ScalarField()) + innerCcs, innerVK, innerWitness, innerProof := getInnerCommit(assert, ecc.BLS12_377.ScalarField(), ecc.BW6_761.ScalarField()) + + // outer proof + circuitVk, err := ValueOfVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerVK) + assert.NoError(err) + circuitWitness, err := ValueOfWitness[sw_bls12377.ScalarField](innerWitness) + assert.NoError(err) + circuitProof, err := ValueOfProof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerProof) + assert.NoError(err) + + outerCircuit := &OuterCircuit[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ + InnerWitness: PlaceholderWitness[sw_bls12377.ScalarField](innerCcs), + Proof: PlaceholderProof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerProof), + VerifyingKey: PlaceholderVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerVK), + } + outerAssignment := &OuterCircuit[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ + InnerWitness: circuitWitness, + Proof: circuitProof, + VerifyingKey: circuitVk, + } + err = test.IsSolved(outerCircuit, outerAssignment, ecc.BW6_761.ScalarField()) + assert.NoError(err) } From 330904c40ffbc4ebf096ae7c982a1a1f16de46bf Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Thu, 16 Nov 2023 23:20:24 +0100 Subject: [PATCH 12/27] fix: compute ith lagrange ok, hashToField failing --- std/recursion/plonk/verifier.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/std/recursion/plonk/verifier.go b/std/recursion/plonk/verifier.go index 787585b6f0..1f551323c1 100644 --- a/std/recursion/plonk/verifier.go +++ b/std/recursion/plonk/verifier.go @@ -467,7 +467,7 @@ func (v *Verifier[FR, G1El, G2El, GtEl]) AssertProof(vk VerifyingKey[FR, G1El, G return err } for i := range vk.CommitmentConstraintIndexes { - li := v.computeIthLagrangeAtZeta(vk.CommitmentConstraintIndexes[i], zeta, zetaPowerM, vk) + li := v.computeIthLagrangeAtZeta(vk.CommitmentConstraintIndexes[i]+vk.NbPublicVariables, zeta, zetaPowerM, vk) marshalledCommitment := v.curve.MarshalG1(proof.Bsb22Commitments[i].G1El) hashToField.Write(marshalledCommitment...) hashedCmt := hashToField.Sum() @@ -733,15 +733,18 @@ func (v *Verifier[FR, G1El, G2El, GtEl]) computeIthLagrangeAtZeta(i uint64, zeta irev := stdbits.Reverse(uint(i)) // skip first zeroes s := irev % 2 + nbBitsUint := 64 for s == 0 { irev = irev >> 1 s = irev % 2 + nbBitsUint-- } - for irev != 0 { + for nbBitsUint != 0 { omegai = v.scalarApi.Mul(omegai, omegai) if irev%2 == 1 { omegai = v.scalarApi.Mul(omegai, &vk.Generator) } + nbBitsUint-- irev = irev >> 1 } @@ -749,6 +752,7 @@ func (v *Verifier[FR, G1El, G2El, GtEl]) computeIthLagrangeAtZeta(i uint64, zeta li := v.scalarApi.Div(num, den) li = v.scalarApi.Mul(li, &vk.SizeInv) + li = v.scalarApi.Mul(li, omegai) return li } From dbff073fac6095f9e5f86bdcdae0c28feed6a255 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 17 Nov 2023 22:14:18 +0300 Subject: [PATCH 13/27] fix: native short hash output size --- std/recursion/wrapped_hash.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/recursion/wrapped_hash.go b/std/recursion/wrapped_hash.go index fff9075c28..a4f8c0893e 100644 --- a/std/recursion/wrapped_hash.go +++ b/std/recursion/wrapped_hash.go @@ -126,7 +126,7 @@ func (h *shortNativeHash) Reset() { } func (h *shortNativeHash) Size() int { - return (int(h.outSize) + 6) / 8 + return (int(h.outSize)+7)/8 - 1 } func (h *shortNativeHash) BlockSize() int { From 5f8a06010dd7966c4fff4fe91c5f48c8cbbe71a5 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 17 Nov 2023 22:51:31 +0300 Subject: [PATCH 14/27] feat: add bw6 --- std/recursion/plonk/verifier.go | 96 ++++++++++++++++++++++++++++ std/recursion/plonk/verifier_test.go | 55 ++++++++++++++++ 2 files changed, 151 insertions(+) diff --git a/std/recursion/plonk/verifier.go b/std/recursion/plonk/verifier.go index 1f551323c1..2b4a4974c2 100644 --- a/std/recursion/plonk/verifier.go +++ b/std/recursion/plonk/verifier.go @@ -8,6 +8,7 @@ import ( fr_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" fr_bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" + fr_bw6761 "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" backend_plonk "github.com/consensys/gnark/backend/plonk" plonkbackend_bls12377 "github.com/consensys/gnark/backend/plonk/bls12-377" plonkbackend_bls12381 "github.com/consensys/gnark/backend/plonk/bls12-381" @@ -22,6 +23,7 @@ import ( "github.com/consensys/gnark/std/algebra" "github.com/consensys/gnark/std/algebra/emulated/sw_bls12381" "github.com/consensys/gnark/std/algebra/emulated/sw_bn254" + "github.com/consensys/gnark/std/algebra/emulated/sw_bw6761" "github.com/consensys/gnark/std/algebra/native/sw_bls12377" "github.com/consensys/gnark/std/algebra/native/sw_bls24315" "github.com/consensys/gnark/std/commitments/kzg" @@ -92,6 +94,43 @@ func ValueOfProof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra if err != nil { return ret, fmt.Errorf("z shifted opening proof value assignment: %w", err) } + case *Proof[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine]: + tProof, ok := proof.(*plonkbackend_bw6761.Proof) + if !ok { + return ret, fmt.Errorf("expected sw_bls12377.Proof, got %T", proof) + } + for i := range r.LRO { + r.LRO[i], err = kzg.ValueOfCommitment[sw_bw6761.G1Affine](tProof.LRO[i]) + if err != nil { + return ret, fmt.Errorf("commitment LRO[%d] value assignment: %w", i, err) + } + } + r.Z, err = kzg.ValueOfCommitment[sw_bw6761.G1Affine](tProof.Z) + if err != nil { + return ret, fmt.Errorf("commitment Z value assignment: %w", err) + } + for i := range r.H { + r.H[i], err = kzg.ValueOfCommitment[sw_bw6761.G1Affine](tProof.H[i]) + if err != nil { + return ret, fmt.Errorf("commitment H[%d] value assignment: %w", i, err) + } + } + r.Bsb22Commitments = make([]kzg.Commitment[sw_bw6761.G1Affine], len(tProof.Bsb22Commitments)) + for i := range r.Bsb22Commitments { + r.Bsb22Commitments[i], err = kzg.ValueOfCommitment[sw_bw6761.G1Affine](tProof.Bsb22Commitments[i]) + if err != nil { + return ret, fmt.Errorf("bsb22 commitment %d value assignment: %w", i, err) + } + } + // TODO: actually we compute the opening point later. Maybe we can precompute it here and later assert its correctness? + r.BatchedProof, err = kzg.ValueOfBatchOpeningProof[sw_bw6761.ScalarField, sw_bw6761.G1Affine](tProof.BatchedProof) + if err != nil { + return ret, fmt.Errorf("batch opening proof value assignment: %w", err) + } + r.ZShiftedOpening, err = kzg.ValueOfOpeningProof[sw_bw6761.ScalarField, sw_bw6761.G1Affine](tProof.ZShiftedOpening) + if err != nil { + return ret, fmt.Errorf("z shifted opening proof value assignment: %w", err) + } default: return ret, fmt.Errorf("unknown parametric type combination: %T", ret) } @@ -233,6 +272,55 @@ func ValueOfVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El } r.CommitmentConstraintIndexes = make([]uint64, len(tVk.CommitmentConstraintIndexes)) copy(r.CommitmentConstraintIndexes, tVk.CommitmentConstraintIndexes) + case *VerifyingKey[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine]: + tVk, ok := vk.(*plonkbackend_bw6761.VerifyingKey) + if !ok { + return ret, fmt.Errorf("expected bls12377.VerifyingKey, got %T", vk) + } + r.Size = tVk.Size + r.SizeInv = sw_bw6761.NewScalar(tVk.SizeInv) + r.Generator = sw_bw6761.NewScalar(tVk.Generator) + r.NbPublicVariables = tVk.NbPublicVariables + r.Kzg, err = kzg.ValueOfVerifyingKey[sw_bw6761.G1Affine, sw_bw6761.G2Affine](tVk.Kzg) + if err != nil { + return ret, fmt.Errorf("verifying key witness assignment: %w", err) + } + r.CosetShift = sw_bw6761.NewScalar(tVk.CosetShift) + for i := range r.S { + r.S[i], err = kzg.ValueOfCommitment[sw_bw6761.G1Affine](tVk.S[i]) + if err != nil { + return ret, fmt.Errorf("commitment S[%d] witness assignment: %w", i, err) + } + } + r.Ql, err = kzg.ValueOfCommitment[sw_bw6761.G1Affine](tVk.Ql) + if err != nil { + return ret, fmt.Errorf("commitment Ql witness assignment: %w", err) + } + r.Qr, err = kzg.ValueOfCommitment[sw_bw6761.G1Affine](tVk.Qr) + if err != nil { + return ret, fmt.Errorf("commitment Qr witness assignment: %w", err) + } + r.Qm, err = kzg.ValueOfCommitment[sw_bw6761.G1Affine](tVk.Qm) + if err != nil { + return ret, fmt.Errorf("commitment Qm witness assignment: %w", err) + } + r.Qo, err = kzg.ValueOfCommitment[sw_bw6761.G1Affine](tVk.Qo) + if err != nil { + return ret, fmt.Errorf("commitment Qo witness assignment: %w", err) + } + r.Qk, err = kzg.ValueOfCommitment[sw_bw6761.G1Affine](tVk.Qk) + if err != nil { + return ret, fmt.Errorf("commitment Qk witness assignment: %w", err) + } + r.Qcp = make([]kzg.Commitment[sw_bw6761.G1Affine], len(tVk.Qcp)) + for i := range r.Qcp { + r.Qcp[i], err = kzg.ValueOfCommitment[sw_bw6761.G1Affine](tVk.Qcp[i]) + if err != nil { + return ret, fmt.Errorf("commitment Qcp[%d] witness assignment: %w", i, err) + } + } + r.CommitmentConstraintIndexes = make([]uint64, len(tVk.CommitmentConstraintIndexes)) + copy(r.CommitmentConstraintIndexes, tVk.CommitmentConstraintIndexes) default: return ret, fmt.Errorf("unknown parametric type combination") } @@ -345,6 +433,14 @@ func ValueOfWitness[FR emulated.FieldParams](w witness.Witness) (Witness[FR], er for i := range vect { s.Public = append(s.Public, sw_bls24315.NewScalar(vect[i])) } + case *Witness[sw_bw6761.ScalarField]: + vect, ok := vec.(fr_bw6761.Vector) + if !ok { + return ret, fmt.Errorf("expected fr_bw6761.Vector, got %T", vec) + } + for i := range vect { + s.Public = append(s.Public, sw_bw6761.NewScalar(vect[i])) + } default: return ret, fmt.Errorf("unknown parametric type combination") } diff --git a/std/recursion/plonk/verifier_test.go b/std/recursion/plonk/verifier_test.go index d6a8e93cbc..967743c46e 100644 --- a/std/recursion/plonk/verifier_test.go +++ b/std/recursion/plonk/verifier_test.go @@ -13,6 +13,7 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/std/algebra" + "github.com/consensys/gnark/std/algebra/emulated/sw_bw6761" "github.com/consensys/gnark/std/algebra/native/sw_bls12377" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/std/recursion" @@ -124,6 +125,33 @@ func TestBLS12InBW6WoCommit(t *testing.T) { // test.NoFuzzing(), test.NoSerializationChecks(), test.NoSolidityChecks()) } +func TestBW6InBN254WoCommit(t *testing.T) { + + assert := test.NewAssert(t) + innerCcs, innerVK, innerWitness, innerProof := getInnerWoCommit(assert, ecc.BW6_761.ScalarField(), ecc.BN254.ScalarField()) + + // outer proof + circuitVk, err := ValueOfVerifyingKey[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerVK) + assert.NoError(err) + circuitWitness, err := ValueOfWitness[sw_bw6761.ScalarField](innerWitness) + assert.NoError(err) + circuitProof, err := ValueOfProof[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerProof) + assert.NoError(err) + + outerCircuit := &OuterCircuit[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{ + InnerWitness: PlaceholderWitness[sw_bw6761.ScalarField](innerCcs), + Proof: PlaceholderProof[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerProof), + VerifyingKey: PlaceholderVerifyingKey[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerVK), + } + outerAssignment := &OuterCircuit[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{ + InnerWitness: circuitWitness, + Proof: circuitProof, + VerifyingKey: circuitVk, + } + err = test.IsSolved(outerCircuit, outerAssignment, ecc.BN254.ScalarField()) + assert.NoError(err) +} + //----------------------------------------------------------------- // With api.Commit @@ -237,3 +265,30 @@ func TestBLS12InBW6Commit(t *testing.T) { assert.NoError(err) } + +func TestBW6InBN254Commit(t *testing.T) { + + assert := test.NewAssert(t) + innerCcs, innerVK, innerWitness, innerProof := getInnerCommit(assert, ecc.BW6_761.ScalarField(), ecc.BN254.ScalarField()) + + // outer proof + circuitVk, err := ValueOfVerifyingKey[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerVK) + assert.NoError(err) + circuitWitness, err := ValueOfWitness[sw_bw6761.ScalarField](innerWitness) + assert.NoError(err) + circuitProof, err := ValueOfProof[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerProof) + assert.NoError(err) + + outerCircuit := &OuterCircuit[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{ + InnerWitness: PlaceholderWitness[sw_bw6761.ScalarField](innerCcs), + Proof: PlaceholderProof[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerProof), + VerifyingKey: PlaceholderVerifyingKey[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerVK), + } + outerAssignment := &OuterCircuit[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{ + InnerWitness: circuitWitness, + Proof: circuitProof, + VerifyingKey: circuitVk, + } + err = test.IsSolved(outerCircuit, outerAssignment, ecc.BN254.ScalarField()) + assert.NoError(err) +} From b7cc8fbb2e6d5dfd8b36c7e7b4d8222a119d5f32 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Mon, 20 Nov 2023 15:23:18 +0100 Subject: [PATCH 15/27] docs: add package documentation --- std/recursion/plonk/verifier.go | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/std/recursion/plonk/verifier.go b/std/recursion/plonk/verifier.go index 2b4a4974c2..076fe0b589 100644 --- a/std/recursion/plonk/verifier.go +++ b/std/recursion/plonk/verifier.go @@ -33,6 +33,9 @@ import ( "github.com/consensys/gnark/std/recursion" ) +// Proof is a typed PLONK proof of SNARK. Use [ValueProof] to initialize the +// witness from the native proof. Use [PlaceholderProof] to initialize the +// placeholder witness for compiling the circuit. type Proof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT] struct { // Commitments to the solution vectors @@ -53,6 +56,9 @@ type Proof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2Elem ZShiftedOpening kzg.OpeningProof[FR, G1El] } +// ValueOfProof returns the typed witness of the native proof. It returns an +// error if there is a mismatch between the type parameters and the provided +// native proof. func ValueOfProof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT](proof backend_plonk.Proof) (Proof[FR, G1El, G2El], error) { var ret Proof[FR, G1El, G2El] var err error @@ -137,6 +143,9 @@ func ValueOfProof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra return ret, nil } +// PlaceholderProof returns a placeholder proof witness to be use for compiling +// the outer circuit for witness alignment. For actual witness assignment use +// [ValueOfProof]. func PlaceholderProof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT](proof backend_plonk.Proof) Proof[FR, G1El, G2El] { switch tproof := proof.(type) { case *plonkbackend_bls12377.Proof: @@ -193,6 +202,8 @@ func PlaceholderProof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El alg } } +// VerifyingKey is a typed PLONK verification key. Use [ValueOfVerifyingKey] or +// [PlaceholderVerifyingKey] for initializing. type VerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT] struct { // Size circuit @@ -219,6 +230,9 @@ type VerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra CommitmentConstraintIndexes []uint64 } +// ValueOfVerifyingKey initializes witness from the given PLONK verifying key. +// It returns an error if there is a mismatch between the type parameters and +// the provided native verifying key. func ValueOfVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT](vk backend_plonk.VerifyingKey) (VerifyingKey[FR, G1El, G2El], error) { var ret VerifyingKey[FR, G1El, G2El] var err error @@ -327,6 +341,8 @@ func ValueOfVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El return ret, nil } +// PlaceholderVerifyingKey returns placeholder of the verification key for +// compiling the outer circuit. func PlaceholderVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT](vk backend_plonk.VerifyingKey) VerifyingKey[FR, G1El, G2El] { switch tvk := vk.(type) { @@ -388,11 +404,13 @@ func PlaceholderVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G // witness use [ValueOfWitness] and to create stub witness for compiling use // [PlaceholderWitness]. type Witness[FR emulated.FieldParams] struct { - // Public is the public inputs. The first element does not need to be one - // wire and is added implicitly during verification. Public []emulated.Element[FR] } +// ValueOfWitness assigns a outer-circuit witness from the inner circuit +// witness. If there is a field mismatch then this method represents the witness +// inputs using field emulation. It returns an error if there is a mismatch +// between the type parameters and provided witness. func ValueOfWitness[FR emulated.FieldParams](w witness.Witness) (Witness[FR], error) { var ret Witness[FR] pubw, err := w.Public() @@ -456,6 +474,7 @@ func PlaceholderWitness[FR emulated.FieldParams](ccs constraint.ConstraintSystem } } +// Verifier verifies PLONK proofs. type Verifier[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT] struct { api frontend.API scalarApi *emulated.Field[FR] @@ -464,6 +483,7 @@ type Verifier[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2E kzg *kzg.Verifier[FR, G1El, G2El, GtEl] } +// NewVerifier returns a new [Verifier] instance. func NewVerifier[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT]( api frontend.API, curve algebra.Curve[FR, G1El], pairing algebra.Pairing[G1El, G2El, GtEl], ) (*Verifier[FR, G1El, G2El, GtEl], error) { @@ -485,6 +505,8 @@ func NewVerifier[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra. }, nil } +// AssertProof asserts that the SNARK proof holds for the given witness and +// verifying key. func (v *Verifier[FR, G1El, G2El, GtEl]) AssertProof(vk VerifyingKey[FR, G1El, G2El], proof Proof[FR, G1El, G2El], witness Witness[FR]) error { var fr FR From 75bf361b48d26fd72635d231a1768e629cfdb947 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Mon, 20 Nov 2023 15:23:33 +0100 Subject: [PATCH 16/27] refactor: describe error in panic --- std/recursion/plonk/verifier.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/std/recursion/plonk/verifier.go b/std/recursion/plonk/verifier.go index 076fe0b589..7c4829a970 100644 --- a/std/recursion/plonk/verifier.go +++ b/std/recursion/plonk/verifier.go @@ -198,7 +198,7 @@ func PlaceholderProof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El alg Bsb22Commitments: make([]kzg.Commitment[G1El], len(tproof.Bsb22Commitments)), } default: - panic("Unrecognised vk") + panic(fmt.Sprintf("unrecognized type parametrization %T", proof)) } } @@ -396,7 +396,8 @@ func PlaceholderVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G Qcp: make([]kzg.Commitment[G1El], len(tvk.Qcp)), } default: - panic("Unrecognised vk") + panic(fmt.Sprintf("unrecognized type parametrization %T", vk)) + } } From 01f28ce4ff8213b9c294635fae09bc62854c9fc1 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Mon, 20 Nov 2023 15:24:13 +0100 Subject: [PATCH 17/27] refactor: init curve and pairing implicitly --- std/recursion/plonk/verifier.go | 13 +++++++++---- std/recursion/plonk/verifier_test.go | 10 +--------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/std/recursion/plonk/verifier.go b/std/recursion/plonk/verifier.go index 7c4829a970..d8c91abd00 100644 --- a/std/recursion/plonk/verifier.go +++ b/std/recursion/plonk/verifier.go @@ -485,10 +485,15 @@ type Verifier[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2E } // NewVerifier returns a new [Verifier] instance. -func NewVerifier[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT]( - api frontend.API, curve algebra.Curve[FR, G1El], pairing algebra.Pairing[G1El, G2El, GtEl], -) (*Verifier[FR, G1El, G2El, GtEl], error) { - // var fr FR +func NewVerifier[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT](api frontend.API) (*Verifier[FR, G1El, G2El, GtEl], error) { + curve, err := algebra.GetCurve[FR, G1El](api) + if err != nil { + return nil, fmt.Errorf("new curve: %w", err) + } + pairing, err := algebra.GetPairing[G1El, G2El, GtEl](api) + if err != nil { + return nil, fmt.Errorf("new pairing: %w", err) + } f, err := emulated.NewField[FR](api) if err != nil { return nil, fmt.Errorf("new scalars: %w", err) diff --git a/std/recursion/plonk/verifier_test.go b/std/recursion/plonk/verifier_test.go index 967743c46e..6548c5912e 100644 --- a/std/recursion/plonk/verifier_test.go +++ b/std/recursion/plonk/verifier_test.go @@ -80,15 +80,7 @@ type OuterCircuit[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra } func (c *OuterCircuit[FR, G1El, G2El, GtEl]) Define(api frontend.API) error { - curve, err := algebra.GetCurve[FR, G1El](api) - if err != nil { - return fmt.Errorf("new curve: %w", err) - } - pairing, err := algebra.GetPairing[G1El, G2El, GtEl](api) - if err != nil { - return fmt.Errorf("get pairing: %w", err) - } - verifier, err := NewVerifier(api, curve, pairing) + verifier, err := NewVerifier[FR, G1El, G2El, GtEl](api) if err != nil { return fmt.Errorf("new verifier: %w", err) } From e608d5709c3157e25a30adba6275c1dbfe8a5ecd Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Mon, 20 Nov 2023 15:24:24 +0100 Subject: [PATCH 18/27] refactor: remove comments --- std/recursion/plonk/verifier_test.go | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/std/recursion/plonk/verifier_test.go b/std/recursion/plonk/verifier_test.go index 6548c5912e..a5a44087ac 100644 --- a/std/recursion/plonk/verifier_test.go +++ b/std/recursion/plonk/verifier_test.go @@ -160,22 +160,13 @@ func (c *InnerCircuitCommit) Define(api frontend.API) error { committer, ok := api.(frontend.Committer) if !ok { - panic("builder does not implement Commit") + return fmt.Errorf("builder does not implement frontend.Committer") } u, err := committer.Commit(x, z) if err != nil { return err } - // v, err := committer.Commit(c.N) - // if err != nil { - // return err - // } - - // api.AssertIsDifferent(v, z) api.AssertIsDifferent(u, c.N) - - // api.AssertIsDifferent(z, c.N) - return nil } From 16d88dbe7b996da4103414e709b8f7ae9d5b486f Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Mon, 20 Nov 2023 15:24:44 +0100 Subject: [PATCH 19/27] docs: add package examples --- std/recursion/plonk/doc.go | 2 + std/recursion/plonk/native_doc_test.go | 82 ++++++++++ std/recursion/plonk/nonnative_doc_test.go | 191 ++++++++++++++++++++++ 3 files changed, 275 insertions(+) create mode 100644 std/recursion/plonk/doc.go create mode 100644 std/recursion/plonk/native_doc_test.go create mode 100644 std/recursion/plonk/nonnative_doc_test.go diff --git a/std/recursion/plonk/doc.go b/std/recursion/plonk/doc.go new file mode 100644 index 0000000000..955477ac83 --- /dev/null +++ b/std/recursion/plonk/doc.go @@ -0,0 +1,2 @@ +// Package plonk implements in-circuit PLONK verifier. +package plonk diff --git a/std/recursion/plonk/native_doc_test.go b/std/recursion/plonk/native_doc_test.go new file mode 100644 index 0000000000..c97e2f4bbc --- /dev/null +++ b/std/recursion/plonk/native_doc_test.go @@ -0,0 +1,82 @@ +package plonk_test + +import ( + "github.com/consensys/gnark-crypto/ecc" + native_plonk "github.com/consensys/gnark/backend/plonk" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/scs" + "github.com/consensys/gnark/std/algebra/native/sw_bls12377" + "github.com/consensys/gnark/std/recursion/plonk" + "github.com/consensys/gnark/test" +) + +// Example of verifying recursively BLS12-371 PLONK proof in BW6-761 PLONK circuit using field emulation +func Example_native() { + // compute the proof which we want to verify recursively + innerCcs, innerVK, innerWitness, innerProof := computeInnerProof(ecc.BW6_761.ScalarField(), ecc.BN254.ScalarField()) + + // initialize the witness elements + circuitVk, err := plonk.ValueOfVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerVK) + if err != nil { + panic(err) + } + circuitWitness, err := plonk.ValueOfWitness[sw_bls12377.ScalarField](innerWitness) + if err != nil { + panic(err) + } + circuitProof, err := plonk.ValueOfProof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerProof) + if err != nil { + panic(err) + } + + outerCircuit := &OuterCircuit[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ + InnerWitness: plonk.PlaceholderWitness[sw_bls12377.ScalarField](innerCcs), + Proof: plonk.PlaceholderProof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerProof), + VerifyingKey: plonk.PlaceholderVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerVK), + } + outerAssignment := &OuterCircuit[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ + InnerWitness: circuitWitness, + Proof: circuitProof, + VerifyingKey: circuitVk, + } + // compile the outer circuit + ccs, err := frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, outerCircuit) + if err != nil { + panic("compile failed: " + err.Error()) + } + + // NB! UNSAFE! Use MPC. + srs, err := test.NewKZGSRS(innerCcs) + if err != nil { + panic(err) + } + // create PLONK setup. NB! UNSAFE + pk, vk, err := native_plonk.Setup(ccs, srs) // UNSAFE! Use MPC + if err != nil { + panic("setup failed: " + err.Error()) + } + + // create prover witness from the assignment + secretWitness, err := frontend.NewWitness(outerAssignment, ecc.BN254.ScalarField()) + if err != nil { + panic("secret witness failed: " + err.Error()) + } + + // create public witness from the assignment + publicWitness, err := secretWitness.Public() + if err != nil { + panic("public witness failed: " + err.Error()) + } + + // construct the PLONK proof of verifying PLONK proof in-circuit + outerProof, err := native_plonk.Prove(ccs, pk, secretWitness) + if err != nil { + panic("proving failed: " + err.Error()) + } + + // verify the Groth16 proof + err = native_plonk.Verify(outerProof, vk, publicWitness) + if err != nil { + panic("circuit verification failed: " + err.Error()) + } +} diff --git a/std/recursion/plonk/nonnative_doc_test.go b/std/recursion/plonk/nonnative_doc_test.go new file mode 100644 index 0000000000..2e7403d810 --- /dev/null +++ b/std/recursion/plonk/nonnative_doc_test.go @@ -0,0 +1,191 @@ +package plonk_test + +import ( + "fmt" + "math/big" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark/backend" + native_plonk "github.com/consensys/gnark/backend/plonk" + "github.com/consensys/gnark/backend/witness" + "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/scs" + "github.com/consensys/gnark/std/algebra" + "github.com/consensys/gnark/std/algebra/emulated/sw_bw6761" + "github.com/consensys/gnark/std/math/emulated" + "github.com/consensys/gnark/std/recursion" + "github.com/consensys/gnark/std/recursion/plonk" + "github.com/consensys/gnark/test" +) + +// InnerCircuitNative is the definition of the inner circuit we want to +// recursively verify inside an outer circuit. The circuit proves the knowledge +// of a factorisation of a semiprime. +type InnerCircuitNative struct { + P, Q frontend.Variable + N frontend.Variable `gnark:",public"` +} + +func (c *InnerCircuitNative) Define(api frontend.API) error { + // prove that P*Q == N + res := api.Mul(c.P, c.Q) + api.AssertIsEqual(res, c.N) + // we must also enforce that P != 1 and Q != 1 + api.AssertIsDifferent(c.P, 1) + api.AssertIsDifferent(c.Q, 1) + return nil +} + +// computeInnerProof computes the proof for the inner circuit we want to verify +// recursively. In this example the PLONK keys are generated on the fly, but +// in practice should be genrated once and using MPC. +func computeInnerProof(field, outer *big.Int) (constraint.ConstraintSystem, native_plonk.VerifyingKey, witness.Witness, native_plonk.Proof) { + innerCcs, err := frontend.Compile(field, scs.NewBuilder, &InnerCircuitNative{}) + if err != nil { + panic(err) + } + // NB! UNSAFE! Use MPC. + srs, err := test.NewKZGSRS(innerCcs) + if err != nil { + panic(err) + } + innerPK, innerVK, err := native_plonk.Setup(innerCcs, srs) + if err != nil { + panic(err) + } + + // inner proof + innerAssignment := &InnerCircuitNative{ + P: 3, + Q: 5, + N: 15, + } + innerWitness, err := frontend.NewWitness(innerAssignment, field) + if err != nil { + panic(err) + } + fsProverHasher, err := recursion.NewShort(outer, field) + if err != nil { + panic(err) + } + kzgProverHasher, err := recursion.NewShort(outer, field) + if err != nil { + panic(err) + } + innerProof, err := native_plonk.Prove(innerCcs, innerPK, innerWitness, + backend.WithProverChallengeHashFunction(fsProverHasher), + backend.WithProverKZGFoldingHashFunction(kzgProverHasher), + ) + if err != nil { + panic(err) + } + innerPubWitness, err := innerWitness.Public() + if err != nil { + panic(err) + } + fsVerifierHasher, err := recursion.NewShort(outer, field) + if err != nil { + panic(err) + } + kzgVerifierHash, err := recursion.NewShort(outer, field) + if err != nil { + panic(err) + } + err = native_plonk.Verify(innerProof, innerVK, innerPubWitness, + backend.WithVerifierChallengeHashFunction(fsVerifierHasher), + backend.WithVerifierKZGFoldingHashFunction(kzgVerifierHash), + ) + if err != nil { + panic(err) + } + return innerCcs, innerVK, innerPubWitness, innerProof +} + +// OuterCircuit is the generic outer circuit which can verify PLONK proofs +// using field emulation or 2-chains of curves. +type OuterCircuit[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT] struct { + Proof plonk.Proof[FR, G1El, G2El] + VerifyingKey plonk.VerifyingKey[FR, G1El, G2El] + InnerWitness plonk.Witness[FR] +} + +func (c *OuterCircuit[FR, G1El, G2El, GtEl]) Define(api frontend.API) error { + verifier, err := plonk.NewVerifier[FR, G1El, G2El, GtEl](api) + if err != nil { + return fmt.Errorf("new verifier: %w", err) + } + err = verifier.AssertProof(c.VerifyingKey, c.Proof, c.InnerWitness) + return err +} + +// Example of verifying recursively BW6-761 PLONK proof in BN254 PLONK circuit using field emulation +func Example_emulated() { + // compute the proof which we want to verify recursively + innerCcs, innerVK, innerWitness, innerProof := computeInnerProof(ecc.BW6_761.ScalarField(), ecc.BN254.ScalarField()) + + // initialize the witness elements + circuitVk, err := plonk.ValueOfVerifyingKey[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerVK) + if err != nil { + panic(err) + } + circuitWitness, err := plonk.ValueOfWitness[sw_bw6761.ScalarField](innerWitness) + if err != nil { + panic(err) + } + circuitProof, err := plonk.ValueOfProof[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerProof) + if err != nil { + panic(err) + } + + outerCircuit := &OuterCircuit[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{ + InnerWitness: plonk.PlaceholderWitness[sw_bw6761.ScalarField](innerCcs), + Proof: plonk.PlaceholderProof[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerProof), + VerifyingKey: plonk.PlaceholderVerifyingKey[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerVK), + } + outerAssignment := &OuterCircuit[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{ + InnerWitness: circuitWitness, + Proof: circuitProof, + VerifyingKey: circuitVk, + } + // compile the outer circuit + ccs, err := frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, outerCircuit) + if err != nil { + panic("compile failed: " + err.Error()) + } + + // NB! UNSAFE! Use MPC. + srs, err := test.NewKZGSRS(innerCcs) + if err != nil { + panic(err) + } + // create PLONK setup. NB! UNSAFE + pk, vk, err := native_plonk.Setup(ccs, srs) // UNSAFE! Use MPC + if err != nil { + panic("setup failed: " + err.Error()) + } + + // create prover witness from the assignment + secretWitness, err := frontend.NewWitness(outerAssignment, ecc.BN254.ScalarField()) + if err != nil { + panic("secret witness failed: " + err.Error()) + } + + // create public witness from the assignment + publicWitness, err := secretWitness.Public() + if err != nil { + panic("public witness failed: " + err.Error()) + } + + // construct the PLONK proof of verifying PLONK proof in-circuit + outerProof, err := native_plonk.Prove(ccs, pk, secretWitness) + if err != nil { + panic("proving failed: " + err.Error()) + } + + // verify the Groth16 proof + err = native_plonk.Verify(outerProof, vk, publicWitness) + if err != nil { + panic("circuit verification failed: " + err.Error()) + } +} From 5860e3a8859f060e93bd1c2034f03eb9e6e70d44 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Mon, 20 Nov 2023 17:41:30 +0100 Subject: [PATCH 20/27] feat: add all supported witness assignments --- std/recursion/plonk/verifier.go | 318 +++++++++++++++++++++++++++----- 1 file changed, 274 insertions(+), 44 deletions(-) diff --git a/std/recursion/plonk/verifier.go b/std/recursion/plonk/verifier.go index d8c91abd00..be98bf99bd 100644 --- a/std/recursion/plonk/verifier.go +++ b/std/recursion/plonk/verifier.go @@ -13,9 +13,7 @@ import ( plonkbackend_bls12377 "github.com/consensys/gnark/backend/plonk/bls12-377" plonkbackend_bls12381 "github.com/consensys/gnark/backend/plonk/bls12-381" plonkbackend_bls24315 "github.com/consensys/gnark/backend/plonk/bls24-315" - plonkbackend_bls24317 "github.com/consensys/gnark/backend/plonk/bls24-317" plonkbackend_bn254 "github.com/consensys/gnark/backend/plonk/bn254" - plonkbackend_bw6633 "github.com/consensys/gnark/backend/plonk/bw6-633" plonkbackend_bw6761 "github.com/consensys/gnark/backend/plonk/bw6-761" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" @@ -100,6 +98,81 @@ func ValueOfProof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra if err != nil { return ret, fmt.Errorf("z shifted opening proof value assignment: %w", err) } + case *Proof[sw_bls12381.ScalarField, sw_bls12381.G1Affine, sw_bls12381.G2Affine]: + tProof, ok := proof.(*plonkbackend_bls12381.Proof) + if !ok { + return ret, fmt.Errorf("expected sw_bls12381.Proof, got %T", proof) + } + for i := range r.LRO { + r.LRO[i], err = kzg.ValueOfCommitment[sw_bls12381.G1Affine](tProof.LRO[i]) + if err != nil { + return ret, fmt.Errorf("commitment LRO[%d] value assignment: %w", i, err) + } + } + r.Z, err = kzg.ValueOfCommitment[sw_bls12381.G1Affine](tProof.Z) + if err != nil { + return ret, fmt.Errorf("commitment Z value assignment: %w", err) + } + for i := range r.H { + r.H[i], err = kzg.ValueOfCommitment[sw_bls12381.G1Affine](tProof.H[i]) + if err != nil { + return ret, fmt.Errorf("commitment H[%d] value assignment: %w", i, err) + } + } + r.Bsb22Commitments = make([]kzg.Commitment[sw_bls12381.G1Affine], len(tProof.Bsb22Commitments)) + for i := range r.Bsb22Commitments { + r.Bsb22Commitments[i], err = kzg.ValueOfCommitment[sw_bls12381.G1Affine](tProof.Bsb22Commitments[i]) + if err != nil { + return ret, fmt.Errorf("bsb22 commitment %d value assignment: %w", i, err) + } + } + // TODO: actually we compute the opening point later. Maybe we can precompute it here and later assert its correctness? + r.BatchedProof, err = kzg.ValueOfBatchOpeningProof[sw_bls12381.ScalarField, sw_bls12381.G1Affine](tProof.BatchedProof) + if err != nil { + return ret, fmt.Errorf("batch opening proof value assignment: %w", err) + } + r.ZShiftedOpening, err = kzg.ValueOfOpeningProof[sw_bls12381.ScalarField, sw_bls12381.G1Affine](tProof.ZShiftedOpening) + if err != nil { + return ret, fmt.Errorf("z shifted opening proof value assignment: %w", err) + } + case *Proof[sw_bls24315.ScalarField, sw_bls24315.G1Affine, sw_bls24315.G2Affine]: + tProof, ok := proof.(*plonkbackend_bls24315.Proof) + if !ok { + return ret, fmt.Errorf("expected sw_bls24315.Proof, got %T", proof) + } + for i := range r.LRO { + r.LRO[i], err = kzg.ValueOfCommitment[sw_bls24315.G1Affine](tProof.LRO[i]) + if err != nil { + return ret, fmt.Errorf("commitment LRO[%d] value assignment: %w", i, err) + } + } + r.Z, err = kzg.ValueOfCommitment[sw_bls24315.G1Affine](tProof.Z) + if err != nil { + return ret, fmt.Errorf("commitment Z value assignment: %w", err) + } + for i := range r.H { + r.H[i], err = kzg.ValueOfCommitment[sw_bls24315.G1Affine](tProof.H[i]) + if err != nil { + return ret, fmt.Errorf("commitment H[%d] value assignment: %w", i, err) + } + } + r.Bsb22Commitments = make([]kzg.Commitment[sw_bls24315.G1Affine], len(tProof.Bsb22Commitments)) + for i := range r.Bsb22Commitments { + r.Bsb22Commitments[i], err = kzg.ValueOfCommitment[sw_bls24315.G1Affine](tProof.Bsb22Commitments[i]) + if err != nil { + return ret, fmt.Errorf("bsb22 commitment %d value assignment: %w", i, err) + } + } + // TODO: actually we compute the opening point later. Maybe we can precompute it here and later assert its correctness? + r.BatchedProof, err = kzg.ValueOfBatchOpeningProof[sw_bls24315.ScalarField, sw_bls24315.G1Affine](tProof.BatchedProof) + if err != nil { + return ret, fmt.Errorf("batch opening proof value assignment: %w", err) + } + r.ZShiftedOpening, err = kzg.ValueOfOpeningProof[sw_bls24315.ScalarField, sw_bls24315.G1Affine](tProof.ZShiftedOpening) + if err != nil { + return ret, fmt.Errorf("z shifted opening proof value assignment: %w", err) + } + case *Proof[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine]: tProof, ok := proof.(*plonkbackend_bw6761.Proof) if !ok { @@ -137,6 +210,44 @@ func ValueOfProof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra if err != nil { return ret, fmt.Errorf("z shifted opening proof value assignment: %w", err) } + case *Proof[sw_bn254.ScalarField, sw_bn254.G1Affine, sw_bn254.G2Affine]: + tProof, ok := proof.(*plonkbackend_bn254.Proof) + if !ok { + return ret, fmt.Errorf("expected sw_bls12377.Proof, got %T", proof) + } + for i := range r.LRO { + r.LRO[i], err = kzg.ValueOfCommitment[sw_bn254.G1Affine](tProof.LRO[i]) + if err != nil { + return ret, fmt.Errorf("commitment LRO[%d] value assignment: %w", i, err) + } + } + r.Z, err = kzg.ValueOfCommitment[sw_bn254.G1Affine](tProof.Z) + if err != nil { + return ret, fmt.Errorf("commitment Z value assignment: %w", err) + } + for i := range r.H { + r.H[i], err = kzg.ValueOfCommitment[sw_bn254.G1Affine](tProof.H[i]) + if err != nil { + return ret, fmt.Errorf("commitment H[%d] value assignment: %w", i, err) + } + } + r.Bsb22Commitments = make([]kzg.Commitment[sw_bn254.G1Affine], len(tProof.Bsb22Commitments)) + for i := range r.Bsb22Commitments { + r.Bsb22Commitments[i], err = kzg.ValueOfCommitment[sw_bn254.G1Affine](tProof.Bsb22Commitments[i]) + if err != nil { + return ret, fmt.Errorf("bsb22 commitment %d value assignment: %w", i, err) + } + } + // TODO: actually we compute the opening point later. Maybe we can precompute it here and later assert its correctness? + r.BatchedProof, err = kzg.ValueOfBatchOpeningProof[sw_bn254.ScalarField, sw_bn254.G1Affine](tProof.BatchedProof) + if err != nil { + return ret, fmt.Errorf("batch opening proof value assignment: %w", err) + } + r.ZShiftedOpening, err = kzg.ValueOfOpeningProof[sw_bn254.ScalarField, sw_bn254.G1Affine](tProof.ZShiftedOpening) + if err != nil { + return ret, fmt.Errorf("z shifted opening proof value assignment: %w", err) + } + // TODO: missing bls12-381, bls24315, bn254, bls24317 default: return ret, fmt.Errorf("unknown parametric type combination: %T", ret) } @@ -155,13 +266,6 @@ func PlaceholderProof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El alg }, Bsb22Commitments: make([]kzg.Commitment[G1El], len(tproof.Bsb22Commitments)), } - case *plonkbackend_bn254.Proof: - return Proof[FR, G1El, G2El]{ - BatchedProof: kzg.BatchOpeningProof[FR, G1El]{ - ClaimedValues: make([]emulated.Element[FR], len(tproof.BatchedProof.ClaimedValues)), - }, - Bsb22Commitments: make([]kzg.Commitment[G1El], len(tproof.Bsb22Commitments)), - } case *plonkbackend_bls12381.Proof: return Proof[FR, G1El, G2El]{ BatchedProof: kzg.BatchOpeningProof[FR, G1El]{ @@ -169,28 +273,21 @@ func PlaceholderProof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El alg }, Bsb22Commitments: make([]kzg.Commitment[G1El], len(tproof.Bsb22Commitments)), } - case *plonkbackend_bw6761.Proof: - return Proof[FR, G1El, G2El]{ - BatchedProof: kzg.BatchOpeningProof[FR, G1El]{ - ClaimedValues: make([]emulated.Element[FR], len(tproof.BatchedProof.ClaimedValues)), - }, - Bsb22Commitments: make([]kzg.Commitment[G1El], len(tproof.Bsb22Commitments)), - } - case *plonkbackend_bls24317.Proof: + case *plonkbackend_bls24315.Proof: return Proof[FR, G1El, G2El]{ BatchedProof: kzg.BatchOpeningProof[FR, G1El]{ ClaimedValues: make([]emulated.Element[FR], len(tproof.BatchedProof.ClaimedValues)), }, Bsb22Commitments: make([]kzg.Commitment[G1El], len(tproof.Bsb22Commitments)), } - case *plonkbackend_bls24315.Proof: + case *plonkbackend_bw6761.Proof: return Proof[FR, G1El, G2El]{ BatchedProof: kzg.BatchOpeningProof[FR, G1El]{ ClaimedValues: make([]emulated.Element[FR], len(tproof.BatchedProof.ClaimedValues)), }, Bsb22Commitments: make([]kzg.Commitment[G1El], len(tproof.Bsb22Commitments)), } - case *plonkbackend_bw6633.Proof: + case *plonkbackend_bn254.Proof: return Proof[FR, G1El, G2El]{ BatchedProof: kzg.BatchOpeningProof[FR, G1El]{ ClaimedValues: make([]emulated.Element[FR], len(tproof.BatchedProof.ClaimedValues)), @@ -286,6 +383,104 @@ func ValueOfVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El } r.CommitmentConstraintIndexes = make([]uint64, len(tVk.CommitmentConstraintIndexes)) copy(r.CommitmentConstraintIndexes, tVk.CommitmentConstraintIndexes) + case *VerifyingKey[sw_bls12381.ScalarField, sw_bls12381.G1Affine, sw_bls12381.G2Affine]: + tVk, ok := vk.(*plonkbackend_bls12381.VerifyingKey) + if !ok { + return ret, fmt.Errorf("expected bls12381.VerifyingKey, got %T", vk) + } + r.Size = tVk.Size + r.SizeInv = sw_bls12381.NewScalar(tVk.SizeInv) + r.Generator = sw_bls12381.NewScalar(tVk.Generator) + r.NbPublicVariables = tVk.NbPublicVariables + r.Kzg, err = kzg.ValueOfVerifyingKey[sw_bls12381.G1Affine, sw_bls12381.G2Affine](tVk.Kzg) + if err != nil { + return ret, fmt.Errorf("verifying key witness assignment: %w", err) + } + r.CosetShift = sw_bls12381.NewScalar(tVk.CosetShift) + for i := range r.S { + r.S[i], err = kzg.ValueOfCommitment[sw_bls12381.G1Affine](tVk.S[i]) + if err != nil { + return ret, fmt.Errorf("commitment S[%d] witness assignment: %w", i, err) + } + } + r.Ql, err = kzg.ValueOfCommitment[sw_bls12381.G1Affine](tVk.Ql) + if err != nil { + return ret, fmt.Errorf("commitment Ql witness assignment: %w", err) + } + r.Qr, err = kzg.ValueOfCommitment[sw_bls12381.G1Affine](tVk.Qr) + if err != nil { + return ret, fmt.Errorf("commitment Qr witness assignment: %w", err) + } + r.Qm, err = kzg.ValueOfCommitment[sw_bls12381.G1Affine](tVk.Qm) + if err != nil { + return ret, fmt.Errorf("commitment Qm witness assignment: %w", err) + } + r.Qo, err = kzg.ValueOfCommitment[sw_bls12381.G1Affine](tVk.Qo) + if err != nil { + return ret, fmt.Errorf("commitment Qo witness assignment: %w", err) + } + r.Qk, err = kzg.ValueOfCommitment[sw_bls12381.G1Affine](tVk.Qk) + if err != nil { + return ret, fmt.Errorf("commitment Qk witness assignment: %w", err) + } + r.Qcp = make([]kzg.Commitment[sw_bls12381.G1Affine], len(tVk.Qcp)) + for i := range r.Qcp { + r.Qcp[i], err = kzg.ValueOfCommitment[sw_bls12381.G1Affine](tVk.Qcp[i]) + if err != nil { + return ret, fmt.Errorf("commitment Qcp[%d] witness assignment: %w", i, err) + } + } + r.CommitmentConstraintIndexes = make([]uint64, len(tVk.CommitmentConstraintIndexes)) + copy(r.CommitmentConstraintIndexes, tVk.CommitmentConstraintIndexes) + case *VerifyingKey[sw_bls24315.ScalarField, sw_bls24315.G1Affine, sw_bls24315.G2Affine]: + tVk, ok := vk.(*plonkbackend_bls24315.VerifyingKey) + if !ok { + return ret, fmt.Errorf("expected bls24315.VerifyingKey, got %T", vk) + } + r.Size = tVk.Size + r.SizeInv = sw_bls24315.NewScalar(tVk.SizeInv) + r.Generator = sw_bls24315.NewScalar(tVk.Generator) + r.NbPublicVariables = tVk.NbPublicVariables + r.Kzg, err = kzg.ValueOfVerifyingKey[sw_bls24315.G1Affine, sw_bls24315.G2Affine](tVk.Kzg) + if err != nil { + return ret, fmt.Errorf("verifying key witness assignment: %w", err) + } + r.CosetShift = sw_bls24315.NewScalar(tVk.CosetShift) + for i := range r.S { + r.S[i], err = kzg.ValueOfCommitment[sw_bls24315.G1Affine](tVk.S[i]) + if err != nil { + return ret, fmt.Errorf("commitment S[%d] witness assignment: %w", i, err) + } + } + r.Ql, err = kzg.ValueOfCommitment[sw_bls24315.G1Affine](tVk.Ql) + if err != nil { + return ret, fmt.Errorf("commitment Ql witness assignment: %w", err) + } + r.Qr, err = kzg.ValueOfCommitment[sw_bls24315.G1Affine](tVk.Qr) + if err != nil { + return ret, fmt.Errorf("commitment Qr witness assignment: %w", err) + } + r.Qm, err = kzg.ValueOfCommitment[sw_bls24315.G1Affine](tVk.Qm) + if err != nil { + return ret, fmt.Errorf("commitment Qm witness assignment: %w", err) + } + r.Qo, err = kzg.ValueOfCommitment[sw_bls24315.G1Affine](tVk.Qo) + if err != nil { + return ret, fmt.Errorf("commitment Qo witness assignment: %w", err) + } + r.Qk, err = kzg.ValueOfCommitment[sw_bls24315.G1Affine](tVk.Qk) + if err != nil { + return ret, fmt.Errorf("commitment Qk witness assignment: %w", err) + } + r.Qcp = make([]kzg.Commitment[sw_bls24315.G1Affine], len(tVk.Qcp)) + for i := range r.Qcp { + r.Qcp[i], err = kzg.ValueOfCommitment[sw_bls24315.G1Affine](tVk.Qcp[i]) + if err != nil { + return ret, fmt.Errorf("commitment Qcp[%d] witness assignment: %w", i, err) + } + } + r.CommitmentConstraintIndexes = make([]uint64, len(tVk.CommitmentConstraintIndexes)) + copy(r.CommitmentConstraintIndexes, tVk.CommitmentConstraintIndexes) case *VerifyingKey[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine]: tVk, ok := vk.(*plonkbackend_bw6761.VerifyingKey) if !ok { @@ -335,6 +530,55 @@ func ValueOfVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El } r.CommitmentConstraintIndexes = make([]uint64, len(tVk.CommitmentConstraintIndexes)) copy(r.CommitmentConstraintIndexes, tVk.CommitmentConstraintIndexes) + case *VerifyingKey[sw_bn254.ScalarField, sw_bn254.G1Affine, sw_bn254.G2Affine]: + tVk, ok := vk.(*plonkbackend_bn254.VerifyingKey) + if !ok { + return ret, fmt.Errorf("expected bn254.VerifyingKey, got %T", vk) + } + r.Size = tVk.Size + r.SizeInv = sw_bn254.NewScalar(tVk.SizeInv) + r.Generator = sw_bn254.NewScalar(tVk.Generator) + r.NbPublicVariables = tVk.NbPublicVariables + r.Kzg, err = kzg.ValueOfVerifyingKey[sw_bn254.G1Affine, sw_bn254.G2Affine](tVk.Kzg) + if err != nil { + return ret, fmt.Errorf("verifying key witness assignment: %w", err) + } + r.CosetShift = sw_bn254.NewScalar(tVk.CosetShift) + for i := range r.S { + r.S[i], err = kzg.ValueOfCommitment[sw_bn254.G1Affine](tVk.S[i]) + if err != nil { + return ret, fmt.Errorf("commitment S[%d] witness assignment: %w", i, err) + } + } + r.Ql, err = kzg.ValueOfCommitment[sw_bn254.G1Affine](tVk.Ql) + if err != nil { + return ret, fmt.Errorf("commitment Ql witness assignment: %w", err) + } + r.Qr, err = kzg.ValueOfCommitment[sw_bn254.G1Affine](tVk.Qr) + if err != nil { + return ret, fmt.Errorf("commitment Qr witness assignment: %w", err) + } + r.Qm, err = kzg.ValueOfCommitment[sw_bn254.G1Affine](tVk.Qm) + if err != nil { + return ret, fmt.Errorf("commitment Qm witness assignment: %w", err) + } + r.Qo, err = kzg.ValueOfCommitment[sw_bn254.G1Affine](tVk.Qo) + if err != nil { + return ret, fmt.Errorf("commitment Qo witness assignment: %w", err) + } + r.Qk, err = kzg.ValueOfCommitment[sw_bn254.G1Affine](tVk.Qk) + if err != nil { + return ret, fmt.Errorf("commitment Qk witness assignment: %w", err) + } + r.Qcp = make([]kzg.Commitment[sw_bn254.G1Affine], len(tVk.Qcp)) + for i := range r.Qcp { + r.Qcp[i], err = kzg.ValueOfCommitment[sw_bn254.G1Affine](tVk.Qcp[i]) + if err != nil { + return ret, fmt.Errorf("commitment Qcp[%d] witness assignment: %w", i, err) + } + } + r.CommitmentConstraintIndexes = make([]uint64, len(tVk.CommitmentConstraintIndexes)) + copy(r.CommitmentConstraintIndexes, tVk.CommitmentConstraintIndexes) default: return ret, fmt.Errorf("unknown parametric type combination") } @@ -353,13 +597,6 @@ func PlaceholderVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, Qcp: make([]kzg.Commitment[G1El], len(tvk.Qcp)), } - case *plonkbackend_bn254.VerifyingKey: - return VerifyingKey[FR, G1El, G2El]{ - Size: tvk.Size, - NbPublicVariables: tvk.NbPublicVariables, - CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, - Qcp: make([]kzg.Commitment[G1El], len(tvk.Qcp)), - } case *plonkbackend_bls12381.VerifyingKey: return VerifyingKey[FR, G1El, G2El]{ Size: tvk.Size, @@ -367,28 +604,21 @@ func PlaceholderVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, Qcp: make([]kzg.Commitment[G1El], len(tvk.Qcp)), } - case *plonkbackend_bw6761.VerifyingKey: - return VerifyingKey[FR, G1El, G2El]{ - Size: tvk.Size, - NbPublicVariables: tvk.NbPublicVariables, - CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, - Qcp: make([]kzg.Commitment[G1El], len(tvk.Qcp)), - } - case *plonkbackend_bls24317.VerifyingKey: + case *plonkbackend_bls24315.VerifyingKey: return VerifyingKey[FR, G1El, G2El]{ Size: tvk.Size, NbPublicVariables: tvk.NbPublicVariables, CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, Qcp: make([]kzg.Commitment[G1El], len(tvk.Qcp)), } - case *plonkbackend_bls24315.VerifyingKey: + case *plonkbackend_bw6761.VerifyingKey: return VerifyingKey[FR, G1El, G2El]{ Size: tvk.Size, NbPublicVariables: tvk.NbPublicVariables, CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, Qcp: make([]kzg.Commitment[G1El], len(tvk.Qcp)), } - case *plonkbackend_bw6633.VerifyingKey: + case *plonkbackend_bn254.VerifyingKey: return VerifyingKey[FR, G1El, G2El]{ Size: tvk.Size, NbPublicVariables: tvk.NbPublicVariables, @@ -420,14 +650,6 @@ func ValueOfWitness[FR emulated.FieldParams](w witness.Witness) (Witness[FR], er } vec := pubw.Vector() switch s := any(&ret).(type) { - case *Witness[sw_bn254.ScalarField]: - vect, ok := vec.(fr_bn254.Vector) - if !ok { - return ret, fmt.Errorf("expected fr_bn254.Vector, got %T", vec) - } - for i := range vect { - s.Public = append(s.Public, sw_bn254.NewScalar(vect[i])) - } case *Witness[sw_bls12377.ScalarField]: vect, ok := vec.(fr_bls12377.Vector) if !ok { @@ -460,6 +682,14 @@ func ValueOfWitness[FR emulated.FieldParams](w witness.Witness) (Witness[FR], er for i := range vect { s.Public = append(s.Public, sw_bw6761.NewScalar(vect[i])) } + case *Witness[sw_bn254.ScalarField]: + vect, ok := vec.(fr_bn254.Vector) + if !ok { + return ret, fmt.Errorf("expected fr_bn254.Vector, got %T", vec) + } + for i := range vect { + s.Public = append(s.Public, sw_bn254.NewScalar(vect[i])) + } default: return ret, fmt.Errorf("unknown parametric type combination") } From 74145f9233a0f82e1097a1d2e3b3c97b4b931fd3 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 23 Nov 2023 11:17:52 +0100 Subject: [PATCH 21/27] test: add MSM test --- .../emulated/sw_emulated/point_test.go | 67 +++++++++++++++++++ std/algebra/native/sw_bls12377/g1_test.go | 61 +++++++++++++++++ std/algebra/native/sw_bls24315/g1_test.go | 61 +++++++++++++++++ 3 files changed, 189 insertions(+) diff --git a/std/algebra/emulated/sw_emulated/point_test.go b/std/algebra/emulated/sw_emulated/point_test.go index 267ccbf3c6..0a3cd8326f 100644 --- a/std/algebra/emulated/sw_emulated/point_test.go +++ b/std/algebra/emulated/sw_emulated/point_test.go @@ -19,6 +19,7 @@ import ( fr_secp "github.com/consensys/gnark-crypto/ecc/secp256k1/fr" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/math/emulated" + "github.com/consensys/gnark/std/math/emulated/emparams" "github.com/consensys/gnark/test" ) @@ -920,3 +921,69 @@ func TestJointScalarMulBase(t *testing.T) { err := test.IsSolved(&circuit, &witness, testCurve.ScalarField()) assert.NoError(err) } + +type MultiScalarMulTest[T, S emulated.FieldParams] struct { + Points []AffinePoint[T] + Scalars []emulated.Element[S] + Res AffinePoint[T] +} + +func (c *MultiScalarMulTest[T, S]) Define(api frontend.API) error { + cr, err := New[T, S](api, GetCurveParams[T]()) + if err != nil { + return err + } + ps := make([]*AffinePoint[T], len(c.Points)) + for i := range c.Points { + ps[i] = &c.Points[i] + } + ss := make([]*emulated.Element[S], len(c.Scalars)) + for i := range c.Scalars { + ss[i] = &c.Scalars[i] + } + res, err := cr.MultiScalarMul(ps, ss) + if err != nil { + return err + } + cr.AssertIsEqual(res, &c.Res) + return nil +} + +func TestMultiScalarMul(t *testing.T) { + assert := test.NewAssert(t) + nbLen := 4 + P := make([]secp256k1.G1Affine, nbLen) + S := make([]fr_secp.Element, nbLen) + for i := 0; i < nbLen; i++ { + S[i].SetRandom() + P[i].ScalarMultiplicationBase(S[i].BigInt(new(big.Int))) + } + var res secp256k1.G1Affine + _, err := res.MultiExp(P, S, ecc.MultiExpConfig{}) + + assert.NoError(err) + cP := make([]AffinePoint[emulated.Secp256k1Fp], len(P)) + for i := range cP { + cP[i] = AffinePoint[emparams.Secp256k1Fp]{ + X: emulated.ValueOf[emparams.Secp256k1Fp](P[i].X), + Y: emulated.ValueOf[emparams.Secp256k1Fp](P[i].Y), + } + } + cS := make([]emulated.Element[emparams.Secp256k1Fr], len(S)) + for i := range cS { + cS[i] = emulated.ValueOf[emparams.Secp256k1Fr](S[i]) + } + assignment := MultiScalarMulTest[emparams.Secp256k1Fp, emparams.Secp256k1Fr]{ + Points: cP, + Scalars: cS, + Res: AffinePoint[emparams.Secp256k1Fp]{ + X: emulated.ValueOf[emparams.Secp256k1Fp](res.X), + Y: emulated.ValueOf[emparams.Secp256k1Fp](res.Y), + }, + } + err = test.IsSolved(&MultiScalarMulTest[emparams.Secp256k1Fp, emparams.P256Fr]{ + Points: make([]AffinePoint[emparams.Secp256k1Fp], nbLen), + Scalars: make([]emulated.Element[emparams.P256Fr], nbLen), + }, &assignment, ecc.BN254.ScalarField()) + assert.NoError(err) +} diff --git a/std/algebra/native/sw_bls12377/g1_test.go b/std/algebra/native/sw_bls12377/g1_test.go index ce10d40732..eb52626127 100644 --- a/std/algebra/native/sw_bls12377/g1_test.go +++ b/std/algebra/native/sw_bls12377/g1_test.go @@ -27,6 +27,7 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/frontend/cs/scs" + "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/test" bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377" @@ -487,6 +488,66 @@ func TestVarScalarMulBaseG1(t *testing.T) { assert.CheckCircuit(&circuit, test.WithValidAssignment(&witness), test.WithCurves(ecc.BW6_761)) } +type MultiScalarMulTest struct { + Points []G1Affine + Scalars []emulated.Element[ScalarField] + Res G1Affine +} + +func (c *MultiScalarMulTest) Define(api frontend.API) error { + cr, err := NewCurve(api) + if err != nil { + return err + } + ps := make([]*G1Affine, len(c.Points)) + for i := range c.Points { + ps[i] = &c.Points[i] + } + ss := make([]*emulated.Element[ScalarField], len(c.Scalars)) + for i := range c.Scalars { + ss[i] = &c.Scalars[i] + } + res, err := cr.MultiScalarMul(ps, ss) + if err != nil { + return err + } + cr.AssertIsEqual(res, &c.Res) + return nil +} + +func TestMultiScalarMul(t *testing.T) { + assert := test.NewAssert(t) + nbLen := 4 + P := make([]bls12377.G1Affine, nbLen) + S := make([]fr.Element, nbLen) + for i := 0; i < nbLen; i++ { + S[i].SetRandom() + P[i].ScalarMultiplicationBase(S[i].BigInt(new(big.Int))) + } + var res bls12377.G1Affine + _, err := res.MultiExp(P, S, ecc.MultiExpConfig{}) + + assert.NoError(err) + cP := make([]G1Affine, len(P)) + for i := range cP { + cP[i] = NewG1Affine(P[i]) + } + cS := make([]emulated.Element[ScalarField], len(S)) + for i := range cS { + cS[i] = NewScalar(S[i]) + } + assignment := MultiScalarMulTest{ + Points: cP, + Scalars: cS, + Res: NewG1Affine(res), + } + err = test.IsSolved(&MultiScalarMulTest{ + Points: make([]G1Affine, nbLen), + Scalars: make([]emulated.Element[ScalarField], nbLen), + }, &assignment, ecc.BW6_761.ScalarField()) + assert.NoError(err) +} + func randomPointG1() bls12377.G1Jac { p1, _, _, _ := bls12377.Generators() diff --git a/std/algebra/native/sw_bls24315/g1_test.go b/std/algebra/native/sw_bls24315/g1_test.go index 524442fbe3..0cff2372d3 100644 --- a/std/algebra/native/sw_bls24315/g1_test.go +++ b/std/algebra/native/sw_bls24315/g1_test.go @@ -27,6 +27,7 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" "github.com/consensys/gnark/frontend/cs/scs" + "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/test" bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315" @@ -489,6 +490,66 @@ func TestVarScalarMulBaseG1(t *testing.T) { assert.CheckCircuit(&circuit, test.WithValidAssignment(&witness), test.WithCurves(ecc.BW6_633), test.NoProverChecks()) } +type MultiScalarMulTest struct { + Points []G1Affine + Scalars []emulated.Element[ScalarField] + Res G1Affine +} + +func (c *MultiScalarMulTest) Define(api frontend.API) error { + cr, err := NewCurve(api) + if err != nil { + return err + } + ps := make([]*G1Affine, len(c.Points)) + for i := range c.Points { + ps[i] = &c.Points[i] + } + ss := make([]*emulated.Element[ScalarField], len(c.Scalars)) + for i := range c.Scalars { + ss[i] = &c.Scalars[i] + } + res, err := cr.MultiScalarMul(ps, ss) + if err != nil { + return err + } + cr.AssertIsEqual(res, &c.Res) + return nil +} + +func TestMultiScalarMul(t *testing.T) { + assert := test.NewAssert(t) + nbLen := 4 + P := make([]bls24315.G1Affine, nbLen) + S := make([]fr.Element, nbLen) + for i := 0; i < nbLen; i++ { + S[i].SetRandom() + P[i].ScalarMultiplicationBase(S[i].BigInt(new(big.Int))) + } + var res bls24315.G1Affine + _, err := res.MultiExp(P, S, ecc.MultiExpConfig{}) + + assert.NoError(err) + cP := make([]G1Affine, len(P)) + for i := range cP { + cP[i] = NewG1Affine(P[i]) + } + cS := make([]emulated.Element[ScalarField], len(S)) + for i := range cS { + cS[i] = NewScalar(S[i]) + } + assignment := MultiScalarMulTest{ + Points: cP, + Scalars: cS, + Res: NewG1Affine(res), + } + err = test.IsSolved(&MultiScalarMulTest{ + Points: make([]G1Affine, nbLen), + Scalars: make([]emulated.Element[ScalarField], nbLen), + }, &assignment, ecc.BW6_633.ScalarField()) + assert.NoError(err) +} + func randomPointG1() bls24315.G1Jac { p1, _, _, _ := bls24315.Generators() From f4fc4635a068355e356ba475e64e9875fdfe37f7 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 23 Nov 2023 11:18:08 +0100 Subject: [PATCH 22/27] fix: remove todo panic --- std/algebra/native/sw_bls12377/pairing2.go | 1 - std/algebra/native/sw_bls24315/pairing2.go | 1 - 2 files changed, 2 deletions(-) diff --git a/std/algebra/native/sw_bls12377/pairing2.go b/std/algebra/native/sw_bls12377/pairing2.go index a8971a3641..a75740febd 100644 --- a/std/algebra/native/sw_bls12377/pairing2.go +++ b/std/algebra/native/sw_bls12377/pairing2.go @@ -76,7 +76,6 @@ func (c *Curve) Add(P, Q *G1Affine) *G1Affine { // AssertIsEqual asserts the equality of P and Q. func (c *Curve) AssertIsEqual(P, Q *G1Affine) { P.AssertIsEqual(c.api, *Q) - panic("todo") } // Neg negates P and returns the result. Does not modify P. diff --git a/std/algebra/native/sw_bls24315/pairing2.go b/std/algebra/native/sw_bls24315/pairing2.go index c75baedc81..a84808ab07 100644 --- a/std/algebra/native/sw_bls24315/pairing2.go +++ b/std/algebra/native/sw_bls24315/pairing2.go @@ -76,7 +76,6 @@ func (c *Curve) Add(P, Q *G1Affine) *G1Affine { // AssertIsEqual asserts the equality of P and Q. func (c *Curve) AssertIsEqual(P, Q *G1Affine) { P.AssertIsEqual(c.api, *Q) - panic("todo") } // Neg negates P and returns the result. Does not modify P. From 51846bfa7732e792f0978feeba0ce245b1d57f74 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 23 Nov 2023 11:54:52 +0100 Subject: [PATCH 23/27] feat: add option shortcuts --- std/recursion/plonk/nonnative_doc_test.go | 28 +---------- std/recursion/plonk/opts.go | 57 +++++++++++++++++++++++ std/recursion/plonk/verifier_test.go | 18 +------ 3 files changed, 61 insertions(+), 42 deletions(-) create mode 100644 std/recursion/plonk/opts.go diff --git a/std/recursion/plonk/nonnative_doc_test.go b/std/recursion/plonk/nonnative_doc_test.go index 2e7403d810..628a2cddd9 100644 --- a/std/recursion/plonk/nonnative_doc_test.go +++ b/std/recursion/plonk/nonnative_doc_test.go @@ -5,7 +5,6 @@ import ( "math/big" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark/backend" native_plonk "github.com/consensys/gnark/backend/plonk" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" @@ -14,7 +13,6 @@ import ( "github.com/consensys/gnark/std/algebra" "github.com/consensys/gnark/std/algebra/emulated/sw_bw6761" "github.com/consensys/gnark/std/math/emulated" - "github.com/consensys/gnark/std/recursion" "github.com/consensys/gnark/std/recursion/plonk" "github.com/consensys/gnark/test" ) @@ -65,18 +63,7 @@ func computeInnerProof(field, outer *big.Int) (constraint.ConstraintSystem, nati if err != nil { panic(err) } - fsProverHasher, err := recursion.NewShort(outer, field) - if err != nil { - panic(err) - } - kzgProverHasher, err := recursion.NewShort(outer, field) - if err != nil { - panic(err) - } - innerProof, err := native_plonk.Prove(innerCcs, innerPK, innerWitness, - backend.WithProverChallengeHashFunction(fsProverHasher), - backend.WithProverKZGFoldingHashFunction(kzgProverHasher), - ) + innerProof, err := native_plonk.Prove(innerCcs, innerPK, innerWitness, plonk.GetNativeProverOptions(outer, field)) if err != nil { panic(err) } @@ -84,18 +71,7 @@ func computeInnerProof(field, outer *big.Int) (constraint.ConstraintSystem, nati if err != nil { panic(err) } - fsVerifierHasher, err := recursion.NewShort(outer, field) - if err != nil { - panic(err) - } - kzgVerifierHash, err := recursion.NewShort(outer, field) - if err != nil { - panic(err) - } - err = native_plonk.Verify(innerProof, innerVK, innerPubWitness, - backend.WithVerifierChallengeHashFunction(fsVerifierHasher), - backend.WithVerifierKZGFoldingHashFunction(kzgVerifierHash), - ) + err = native_plonk.Verify(innerProof, innerVK, innerPubWitness, plonk.GetNativeVerifierOptions(outer, field)) if err != nil { panic(err) } diff --git a/std/recursion/plonk/opts.go b/std/recursion/plonk/opts.go new file mode 100644 index 0000000000..cfb22836c7 --- /dev/null +++ b/std/recursion/plonk/opts.go @@ -0,0 +1,57 @@ +package plonk + +import ( + "fmt" + "math/big" + + "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/std/recursion" +) + +// GetNativeProverOptions returns PLONK prover options for the native prover to +// initialize the configuration suitable for in-circuit verification. +func GetNativeProverOptions(outer, field *big.Int) backend.ProverOption { + return func(pc *backend.ProverConfig) error { + fsProverHasher, err := recursion.NewShort(outer, field) + if err != nil { + return fmt.Errorf("get prover fs hash: %w", err) + } + kzgProverHasher, err := recursion.NewShort(outer, field) + if err != nil { + return fmt.Errorf("get prover kzg hash") + } + fsOpt := backend.WithProverChallengeHashFunction(fsProverHasher) + if err = fsOpt(pc); err != nil { + return fmt.Errorf("apply verifier fs hash option: %w", err) + } + kzgOpt := backend.WithProverKZGFoldingHashFunction(kzgProverHasher) + if err = kzgOpt(pc); err != nil { + return fmt.Errorf("apply verifier kzg folding hash option: %w", err) + } + return nil + } +} + +// GetNativeVerifierOptions returns PLONK verifier options to initialize the +// configuration to be compatible with in-circuit verification. +func GetNativeVerifierOptions(outer, field *big.Int) backend.VerifierOption { + return func(vc *backend.VerifierConfig) error { + fsVerifierHasher, err := recursion.NewShort(outer, field) + if err != nil { + return fmt.Errorf("get verifier fs hash: %w", err) + } + kzgVerifierHasher, err := recursion.NewShort(outer, field) + if err != nil { + return fmt.Errorf("get verifier kzg hash: %w", err) + } + fsOpt := backend.WithVerifierChallengeHashFunction(fsVerifierHasher) + if err = fsOpt(vc); err != nil { + return fmt.Errorf("apply verifier fs hash option: %w", err) + } + kzgOpt := backend.WithVerifierKZGFoldingHashFunction(kzgVerifierHasher) + if err = kzgOpt(vc); err != nil { + return fmt.Errorf("apply verifier kzg folding hash option: %w", err) + } + return nil + } +} diff --git a/std/recursion/plonk/verifier_test.go b/std/recursion/plonk/verifier_test.go index a5a44087ac..ec63435003 100644 --- a/std/recursion/plonk/verifier_test.go +++ b/std/recursion/plonk/verifier_test.go @@ -50,25 +50,11 @@ func getInnerWoCommit(assert *test.Assert, field, outer *big.Int) (constraint.Co } innerWitness, err := frontend.NewWitness(innerAssignment, field) assert.NoError(err) - fsProverHasher, err := recursion.NewShort(outer, field) - assert.NoError(err) - kzgProverHasher, err := recursion.NewShort(outer, field) - assert.NoError(err) - innerProof, err := plonk.Prove(innerCcs, innerPK, innerWitness, - backend.WithProverChallengeHashFunction(fsProverHasher), - backend.WithProverKZGFoldingHashFunction(kzgProverHasher), - ) + innerProof, err := plonk.Prove(innerCcs, innerPK, innerWitness, GetNativeProverOptions(outer, field)) assert.NoError(err) innerPubWitness, err := innerWitness.Public() assert.NoError(err) - fsVerifierHasher, err := recursion.NewShort(outer, field) - assert.NoError(err) - kzgVerifierHash, err := recursion.NewShort(outer, field) - assert.NoError(err) - err = plonk.Verify(innerProof, innerVK, innerPubWitness, - backend.WithVerifierChallengeHashFunction(fsVerifierHasher), - backend.WithVerifierKZGFoldingHashFunction(kzgVerifierHash), - ) + err = plonk.Verify(innerProof, innerVK, innerPubWitness, GetNativeVerifierOptions(outer, field)) assert.NoError(err) return innerCcs, innerVK, innerPubWitness, innerProof } From 9e3d25065c03ff6da570d0e4e6d8d5efe2f7a04b Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 28 Nov 2023 11:13:00 +0100 Subject: [PATCH 24/27] fix: include hash to field in shortcut option --- std/recursion/plonk/opts.go | 23 ++++++++++++++++++++--- std/recursion/plonk/verifier_test.go | 27 ++------------------------- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/std/recursion/plonk/opts.go b/std/recursion/plonk/opts.go index cfb22836c7..7941e2b3d1 100644 --- a/std/recursion/plonk/opts.go +++ b/std/recursion/plonk/opts.go @@ -18,17 +18,26 @@ func GetNativeProverOptions(outer, field *big.Int) backend.ProverOption { } kzgProverHasher, err := recursion.NewShort(outer, field) if err != nil { - return fmt.Errorf("get prover kzg hash") + return fmt.Errorf("get prover kzg hash: %w", err) + } + htfProverHasher, err := recursion.NewShort(outer, field) + if err != nil { + return fmt.Errorf("get hash to field: %w", err) } fsOpt := backend.WithProverChallengeHashFunction(fsProverHasher) if err = fsOpt(pc); err != nil { - return fmt.Errorf("apply verifier fs hash option: %w", err) + return fmt.Errorf("apply prover fs hash option: %w", err) } kzgOpt := backend.WithProverKZGFoldingHashFunction(kzgProverHasher) if err = kzgOpt(pc); err != nil { - return fmt.Errorf("apply verifier kzg folding hash option: %w", err) + return fmt.Errorf("apply prover kzg folding hash option: %w", err) + } + htfOpt := backend.WithProverHashToFieldFunction(htfProverHasher) + if err = htfOpt(pc); err != nil { + return fmt.Errorf("apply prover htf option: %w", err) } return nil + } } @@ -44,6 +53,10 @@ func GetNativeVerifierOptions(outer, field *big.Int) backend.VerifierOption { if err != nil { return fmt.Errorf("get verifier kzg hash: %w", err) } + htfVerifierHasher, err := recursion.NewShort(outer, field) + if err != nil { + return fmt.Errorf("get hash to field: %w", err) + } fsOpt := backend.WithVerifierChallengeHashFunction(fsVerifierHasher) if err = fsOpt(vc); err != nil { return fmt.Errorf("apply verifier fs hash option: %w", err) @@ -52,6 +65,10 @@ func GetNativeVerifierOptions(outer, field *big.Int) backend.VerifierOption { if err = kzgOpt(vc); err != nil { return fmt.Errorf("apply verifier kzg folding hash option: %w", err) } + htfOpt := backend.WithVerifierHashToFieldFunction(htfVerifierHasher) + if err = htfOpt(vc); err != nil { + return fmt.Errorf("apply verifier htf option: %w", err) + } return nil } } diff --git a/std/recursion/plonk/verifier_test.go b/std/recursion/plonk/verifier_test.go index ec63435003..96deeb66a9 100644 --- a/std/recursion/plonk/verifier_test.go +++ b/std/recursion/plonk/verifier_test.go @@ -6,7 +6,6 @@ import ( "testing" "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark/backend" "github.com/consensys/gnark/backend/plonk" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" @@ -16,7 +15,6 @@ import ( "github.com/consensys/gnark/std/algebra/emulated/sw_bw6761" "github.com/consensys/gnark/std/algebra/native/sw_bls12377" "github.com/consensys/gnark/std/math/emulated" - "github.com/consensys/gnark/std/recursion" "github.com/consensys/gnark/test" ) @@ -175,33 +173,12 @@ func getInnerCommit(assert *test.Assert, field, outer *big.Int) (constraint.Cons } innerWitness, err := frontend.NewWitness(innerAssignment, field) assert.NoError(err) - fsProverHasher, err := recursion.NewShort(outer, field) - assert.NoError(err) - kzgProverHasher, err := recursion.NewShort(outer, field) - assert.NoError(err) - htfProverdHasher, err := recursion.NewShort(outer, field) - assert.NoError(err) - innerProof, err := plonk.Prove(innerCcs, innerPK, innerWitness, - backend.WithProverChallengeHashFunction(fsProverHasher), - backend.WithProverKZGFoldingHashFunction(kzgProverHasher), - backend.WithProverHashToFieldFunction(htfProverdHasher), - ) + innerProof, err := plonk.Prove(innerCcs, innerPK, innerWitness, GetNativeProverOptions(outer, field)) assert.NoError(err) innerPubWitness, err := innerWitness.Public() assert.NoError(err) - fsVerifierHasher, err := recursion.NewShort(outer, field) - assert.NoError(err) - kzgVerifierHash, err := recursion.NewShort(outer, field) - assert.NoError(err) - htfVerifierHasher, err := recursion.NewShort(outer, field) - assert.NoError(err) - err = plonk.Verify(innerProof, innerVK, innerPubWitness, - backend.WithVerifierChallengeHashFunction(fsVerifierHasher), - backend.WithVerifierKZGFoldingHashFunction(kzgVerifierHash), - backend.WithVerifierHashToFieldFunction(htfVerifierHasher), - ) - // backend.WithVerifierChallengeHashFunction(fsProverHasher), + err = plonk.Verify(innerProof, innerVK, innerPubWitness, GetNativeVerifierOptions(outer, field)) assert.NoError(err) return innerCcs, innerVK, innerPubWitness, innerProof From a3ec4839b9c6672b441a28e9a6cbcda53c10cb27 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 28 Nov 2023 11:58:36 +0100 Subject: [PATCH 25/27] feat: use only CCS for placeholder proof and verifyingkey --- std/recursion/plonk/native_doc_test.go | 4 +- std/recursion/plonk/nonnative_doc_test.go | 4 +- std/recursion/plonk/verifier.go | 103 +++++----------------- std/recursion/plonk/verifier_test.go | 16 ++-- 4 files changed, 35 insertions(+), 92 deletions(-) diff --git a/std/recursion/plonk/native_doc_test.go b/std/recursion/plonk/native_doc_test.go index c97e2f4bbc..89e7f1aa32 100644 --- a/std/recursion/plonk/native_doc_test.go +++ b/std/recursion/plonk/native_doc_test.go @@ -31,8 +31,8 @@ func Example_native() { outerCircuit := &OuterCircuit[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ InnerWitness: plonk.PlaceholderWitness[sw_bls12377.ScalarField](innerCcs), - Proof: plonk.PlaceholderProof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerProof), - VerifyingKey: plonk.PlaceholderVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerVK), + Proof: plonk.PlaceholderProof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerCcs), + VerifyingKey: plonk.PlaceholderVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerCcs), } outerAssignment := &OuterCircuit[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ InnerWitness: circuitWitness, diff --git a/std/recursion/plonk/nonnative_doc_test.go b/std/recursion/plonk/nonnative_doc_test.go index 628a2cddd9..b3867b1b8c 100644 --- a/std/recursion/plonk/nonnative_doc_test.go +++ b/std/recursion/plonk/nonnative_doc_test.go @@ -116,8 +116,8 @@ func Example_emulated() { outerCircuit := &OuterCircuit[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{ InnerWitness: plonk.PlaceholderWitness[sw_bw6761.ScalarField](innerCcs), - Proof: plonk.PlaceholderProof[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerProof), - VerifyingKey: plonk.PlaceholderVerifyingKey[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerVK), + Proof: plonk.PlaceholderProof[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerCcs), + VerifyingKey: plonk.PlaceholderVerifyingKey[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerCcs), } outerAssignment := &OuterCircuit[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{ InnerWitness: circuitWitness, diff --git a/std/recursion/plonk/verifier.go b/std/recursion/plonk/verifier.go index be98bf99bd..92fb080fb1 100644 --- a/std/recursion/plonk/verifier.go +++ b/std/recursion/plonk/verifier.go @@ -257,46 +257,15 @@ func ValueOfProof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra // PlaceholderProof returns a placeholder proof witness to be use for compiling // the outer circuit for witness alignment. For actual witness assignment use // [ValueOfProof]. -func PlaceholderProof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT](proof backend_plonk.Proof) Proof[FR, G1El, G2El] { - switch tproof := proof.(type) { - case *plonkbackend_bls12377.Proof: - return Proof[FR, G1El, G2El]{ - BatchedProof: kzg.BatchOpeningProof[FR, G1El]{ - ClaimedValues: make([]emulated.Element[FR], len(tproof.BatchedProof.ClaimedValues)), - }, - Bsb22Commitments: make([]kzg.Commitment[G1El], len(tproof.Bsb22Commitments)), - } - case *plonkbackend_bls12381.Proof: - return Proof[FR, G1El, G2El]{ - BatchedProof: kzg.BatchOpeningProof[FR, G1El]{ - ClaimedValues: make([]emulated.Element[FR], len(tproof.BatchedProof.ClaimedValues)), - }, - Bsb22Commitments: make([]kzg.Commitment[G1El], len(tproof.Bsb22Commitments)), - } - case *plonkbackend_bls24315.Proof: - return Proof[FR, G1El, G2El]{ - BatchedProof: kzg.BatchOpeningProof[FR, G1El]{ - ClaimedValues: make([]emulated.Element[FR], len(tproof.BatchedProof.ClaimedValues)), - }, - Bsb22Commitments: make([]kzg.Commitment[G1El], len(tproof.Bsb22Commitments)), - } - case *plonkbackend_bw6761.Proof: - return Proof[FR, G1El, G2El]{ - BatchedProof: kzg.BatchOpeningProof[FR, G1El]{ - ClaimedValues: make([]emulated.Element[FR], len(tproof.BatchedProof.ClaimedValues)), - }, - Bsb22Commitments: make([]kzg.Commitment[G1El], len(tproof.Bsb22Commitments)), - } - case *plonkbackend_bn254.Proof: - return Proof[FR, G1El, G2El]{ - BatchedProof: kzg.BatchOpeningProof[FR, G1El]{ - ClaimedValues: make([]emulated.Element[FR], len(tproof.BatchedProof.ClaimedValues)), - }, - Bsb22Commitments: make([]kzg.Commitment[G1El], len(tproof.Bsb22Commitments)), - } - default: - panic(fmt.Sprintf("unrecognized type parametrization %T", proof)) +func PlaceholderProof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT](ccs constraint.ConstraintSystem) Proof[FR, G1El, G2El] { + nbCommitments := len(ccs.GetCommitments().CommitmentIndexes()) + ret := Proof[FR, G1El, G2El]{ + BatchedProof: kzg.BatchOpeningProof[FR, G1El]{ + ClaimedValues: make([]emulated.Element[FR], 7+nbCommitments), + }, + Bsb22Commitments: make([]kzg.Commitment[G1El], nbCommitments), } + return ret } // VerifyingKey is a typed PLONK verification key. Use [ValueOfVerifyingKey] or @@ -587,47 +556,21 @@ func ValueOfVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El // PlaceholderVerifyingKey returns placeholder of the verification key for // compiling the outer circuit. -func PlaceholderVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT](vk backend_plonk.VerifyingKey) VerifyingKey[FR, G1El, G2El] { - - switch tvk := vk.(type) { - case *plonkbackend_bls12377.VerifyingKey: - return VerifyingKey[FR, G1El, G2El]{ - Size: tvk.Size, - NbPublicVariables: tvk.NbPublicVariables, - CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, - Qcp: make([]kzg.Commitment[G1El], len(tvk.Qcp)), - } - case *plonkbackend_bls12381.VerifyingKey: - return VerifyingKey[FR, G1El, G2El]{ - Size: tvk.Size, - NbPublicVariables: tvk.NbPublicVariables, - CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, - Qcp: make([]kzg.Commitment[G1El], len(tvk.Qcp)), - } - case *plonkbackend_bls24315.VerifyingKey: - return VerifyingKey[FR, G1El, G2El]{ - Size: tvk.Size, - NbPublicVariables: tvk.NbPublicVariables, - CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, - Qcp: make([]kzg.Commitment[G1El], len(tvk.Qcp)), - } - case *plonkbackend_bw6761.VerifyingKey: - return VerifyingKey[FR, G1El, G2El]{ - Size: tvk.Size, - NbPublicVariables: tvk.NbPublicVariables, - CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, - Qcp: make([]kzg.Commitment[G1El], len(tvk.Qcp)), - } - case *plonkbackend_bn254.VerifyingKey: - return VerifyingKey[FR, G1El, G2El]{ - Size: tvk.Size, - NbPublicVariables: tvk.NbPublicVariables, - CommitmentConstraintIndexes: tvk.CommitmentConstraintIndexes, - Qcp: make([]kzg.Commitment[G1El], len(tvk.Qcp)), - } - default: - panic(fmt.Sprintf("unrecognized type parametrization %T", vk)) - +func PlaceholderVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT](ccs constraint.ConstraintSystem) VerifyingKey[FR, G1El, G2El] { + nbPublic := ccs.GetNbPublicVariables() + nbConstraints := ccs.GetNbConstraints() + sizeSystem := nbPublic + nbConstraints + nextPowerTwo := 1 << stdbits.Len(uint(sizeSystem)) + commitmentIndexes := ccs.GetCommitments().CommitmentIndexes() + cCommitmentIndexes := make([]uint64, len(commitmentIndexes)) + for i := range cCommitmentIndexes { + cCommitmentIndexes[i] = uint64(commitmentIndexes[i]) + } + return VerifyingKey[FR, G1El, G2El]{ + Size: uint64(nextPowerTwo), + NbPublicVariables: uint64(nbPublic), + CommitmentConstraintIndexes: cCommitmentIndexes, + Qcp: make([]kzg.Commitment[G1El], len(commitmentIndexes)), } } diff --git a/std/recursion/plonk/verifier_test.go b/std/recursion/plonk/verifier_test.go index 96deeb66a9..b84b2b5dda 100644 --- a/std/recursion/plonk/verifier_test.go +++ b/std/recursion/plonk/verifier_test.go @@ -87,8 +87,8 @@ func TestBLS12InBW6WoCommit(t *testing.T) { outerCircuit := &OuterCircuit[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ InnerWitness: PlaceholderWitness[sw_bls12377.ScalarField](innerCcs), - Proof: PlaceholderProof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerProof), - VerifyingKey: PlaceholderVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerVK), + Proof: PlaceholderProof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerCcs), + VerifyingKey: PlaceholderVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerCcs), } outerAssignment := &OuterCircuit[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ InnerWitness: circuitWitness, @@ -116,8 +116,8 @@ func TestBW6InBN254WoCommit(t *testing.T) { outerCircuit := &OuterCircuit[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{ InnerWitness: PlaceholderWitness[sw_bw6761.ScalarField](innerCcs), - Proof: PlaceholderProof[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerProof), - VerifyingKey: PlaceholderVerifyingKey[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerVK), + Proof: PlaceholderProof[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerCcs), + VerifyingKey: PlaceholderVerifyingKey[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerCcs), } outerAssignment := &OuterCircuit[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{ InnerWitness: circuitWitness, @@ -199,8 +199,8 @@ func TestBLS12InBW6Commit(t *testing.T) { outerCircuit := &OuterCircuit[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ InnerWitness: PlaceholderWitness[sw_bls12377.ScalarField](innerCcs), - Proof: PlaceholderProof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerProof), - VerifyingKey: PlaceholderVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerVK), + Proof: PlaceholderProof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerCcs), + VerifyingKey: PlaceholderVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerCcs), } outerAssignment := &OuterCircuit[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ InnerWitness: circuitWitness, @@ -227,8 +227,8 @@ func TestBW6InBN254Commit(t *testing.T) { outerCircuit := &OuterCircuit[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{ InnerWitness: PlaceholderWitness[sw_bw6761.ScalarField](innerCcs), - Proof: PlaceholderProof[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerProof), - VerifyingKey: PlaceholderVerifyingKey[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerVK), + Proof: PlaceholderProof[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerCcs), + VerifyingKey: PlaceholderVerifyingKey[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerCcs), } outerAssignment := &OuterCircuit[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{ InnerWitness: circuitWitness, From 3608b290fe0540130470e6daf5cafb944157a3a5 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 28 Nov 2023 11:58:48 +0100 Subject: [PATCH 26/27] chore: typos and cleanup --- std/recursion/plonk/nonnative_doc_test.go | 2 +- std/recursion/plonk/verifier.go | 2 +- std/recursion/plonk/verifier_test.go | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/std/recursion/plonk/nonnative_doc_test.go b/std/recursion/plonk/nonnative_doc_test.go index b3867b1b8c..d9d34e326b 100644 --- a/std/recursion/plonk/nonnative_doc_test.go +++ b/std/recursion/plonk/nonnative_doc_test.go @@ -159,7 +159,7 @@ func Example_emulated() { panic("proving failed: " + err.Error()) } - // verify the Groth16 proof + // verify the PLONK proof err = native_plonk.Verify(outerProof, vk, publicWitness) if err != nil { panic("circuit verification failed: " + err.Error()) diff --git a/std/recursion/plonk/verifier.go b/std/recursion/plonk/verifier.go index 92fb080fb1..cc912dccc0 100644 --- a/std/recursion/plonk/verifier.go +++ b/std/recursion/plonk/verifier.go @@ -31,7 +31,7 @@ import ( "github.com/consensys/gnark/std/recursion" ) -// Proof is a typed PLONK proof of SNARK. Use [ValueProof] to initialize the +// Proof is a typed PLONK proof of SNARK. Use [ValueOfProof] to initialize the // witness from the native proof. Use [PlaceholderProof] to initialize the // placeholder witness for compiling the circuit. type Proof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT] struct { diff --git a/std/recursion/plonk/verifier_test.go b/std/recursion/plonk/verifier_test.go index b84b2b5dda..924ac141f7 100644 --- a/std/recursion/plonk/verifier_test.go +++ b/std/recursion/plonk/verifier_test.go @@ -97,8 +97,6 @@ func TestBLS12InBW6WoCommit(t *testing.T) { } err = test.IsSolved(outerCircuit, outerAssignment, ecc.BW6_761.ScalarField()) assert.NoError(err) - // assert.CheckCircuit(outerCircuit, test.WithValidAssignment(outerAssignment), test.WithCurves(ecc.BW6_761), - // test.NoFuzzing(), test.NoSerializationChecks(), test.NoSolidityChecks()) } func TestBW6InBN254WoCommit(t *testing.T) { From f31664bd00b9925f57febe73ccef8caec30b9cc7 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 28 Nov 2023 12:08:44 +0100 Subject: [PATCH 27/27] docs: add KZG package documentation --- std/commitments/kzg/verifier.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/std/commitments/kzg/verifier.go b/std/commitments/kzg/verifier.go index d284a87be8..eb29938b21 100644 --- a/std/commitments/kzg/verifier.go +++ b/std/commitments/kzg/verifier.go @@ -365,6 +365,7 @@ func (v *Verifier[FR, G1El, G2El, GTEl]) CheckOpeningProof(commitment Commitment return nil } +// BatchVerifySinglePoint verifies multiple opening proofs at a single point. func (v *Verifier[FR, G1El, G2El, GTEl]) BatchVerifySinglePoint(digests []Commitment[G1El], batchOpeningProof BatchOpeningProof[FR, G1El], point emulated.Element[FR], vk VerifyingKey[G1El, G2El], dataTranscript ...emulated.Element[FR]) error { // fold the proof foldedProof, foldedDigest, err := v.FoldProof(digests, batchOpeningProof, point, dataTranscript...) @@ -379,6 +380,7 @@ func (v *Verifier[FR, G1El, G2El, GTEl]) BatchVerifySinglePoint(digests []Commit return nil } +// BatchVerifyMultiPoints verifies multiple opening proofs at different points. func (v *Verifier[FR, G1El, G2El, GTEl]) BatchVerifyMultiPoints(digests []Commitment[G1El], proofs []OpeningProof[FR, G1El], points []emulated.Element[FR], vk VerifyingKey[G1El, G2El]) error { var fr FR @@ -490,6 +492,7 @@ func (v *Verifier[FR, G1El, G2El, GTEl]) BatchVerifyMultiPoints(digests []Commit return err } +// FoldProof folds multiple commitments and a batch opening proof for a single opening check. func (v *Verifier[FR, G1El, G2El, GTEl]) FoldProof(digests []Commitment[G1El], batchOpeningProof BatchOpeningProof[FR, G1El], point emulated.Element[FR], dataTranscript ...emulated.Element[FR]) (OpeningProof[FR, G1El], Commitment[G1El], error) { var retP OpeningProof[FR, G1El] var retC Commitment[G1El]