From 65cb3e59f6f96dec52a81d2e792dccdb5b744646 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Thu, 26 Oct 2023 23:10:43 +0200 Subject: [PATCH 01/15] feat: refactored kzg verified with native emulatedElement[S] --- std/commitments/kzg_refactor/verifier.go | 301 +++++++++++++++++++++++ 1 file changed, 301 insertions(+) create mode 100644 std/commitments/kzg_refactor/verifier.go diff --git a/std/commitments/kzg_refactor/verifier.go b/std/commitments/kzg_refactor/verifier.go new file mode 100644 index 0000000000..ae0995ca32 --- /dev/null +++ b/std/commitments/kzg_refactor/verifier.go @@ -0,0 +1,301 @@ +package kzg_refactor + +import ( + "errors" + "fmt" + + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/algebra" + "github.com/consensys/gnark/std/hash" + "github.com/consensys/gnark/std/math/emulated" +) + +var ( + ErrInvalidNbDigests = errors.New("number of digests is not the same as the number of polynomials") + ErrZeroNbDigests = errors.New("number of digests is zero") +) + +// Commitment is an KZG commitment to a polynomial. Use [ValueOfCommitment] to +// initialize a witness from the native commitment. +type Commitment[G1El any] struct { + G1El G1El +} + +// OpeningProof embeds the opening proof that polynomial evaluated at Point is +// equal to ClaimedValue. Use [ValueOfOpeningProof] to initialize a witness from +// a native opening proof. +type OpeningProof[S emulated.FieldParams, G1El any] struct { + Quotient G1El + ClaimedValue emulated.Element[S] +} + +// VerifyingKey is the trusted setup for KZG polynomial commitment scheme. Use +// [ValueOfVerifyingKey] to initialize a witness from the native VerifyingKey. +type VerifyingKey[G1El, G2El any] struct { + G2 [2]G2El + G1 G1El +} + +type BatchOpeningProof[S emulated.FieldParams, G1El any] struct { + Quotient G1El + ClaimedValues []emulated.Element[S] +} + +// B base field, S scalar +// S here is emulated.Element[S] +type IVerifier[S emulated.FieldParams, G1El, G2El any] interface { + CheckOpeningProof(Commitment[G1El], OpeningProof[S, G1El], emulated.Element[S], VerifyingKey[G1El, G2El]) error + FoldProof([]Commitment[G1El], BatchOpeningProof[S, G1El], emulated.Element[S], hash.FieldHasher, ...frontend.Variable) (OpeningProof[S, G1El], Commitment[G1El], error) + BatchVerifySinglePoint([]Commitment[G1El], BatchOpeningProof[S, G1El], emulated.Element[S], VerifyingKey[G1El, G2El], hash.FieldHasher, ...frontend.Variable) error + BatchVerifyMultiPoints([]Commitment[G1El], []OpeningProof[S, G1El], []emulated.Element[S], VerifyingKey[G1El, G2El]) error +} + +type Verifier[S emulated.FieldParams, G1El, G2El, GtEl any] struct { + api frontend.API + scalarApi *emulated.Field[S] + ec algebra.Curve[emulated.Element[S], G1El] + pairing algebra.Pairing[G1El, G2El, GtEl] +} + +func NewVerifier[S emulated.FieldParams, G1El, G2El, GtEl any](api frontend.API) (Verifier[S, G1El, G2El, GtEl], error) { + var res Verifier[S, G1El, G2El, GtEl] + var err error + res.api = api + res.ec, err = algebra.GetCurve[emulated.Element[S], G1El](api) + if err != nil { + return res, err + } + res.scalarApi, err = emulated.NewField[S](api) + if err != nil { + return res, err + } + res.pairing, err = algebra.GetPairing[G1El, G2El, GtEl](api) + if err != nil { + return res, err + } + + return res, nil +} + +// S here is emulated.FieldParams +func (v *Verifier[S, G1El, G2El, GTEl]) CheckOpeningProof(digest Commitment[G1El], proof OpeningProof[S, G1El], point emulated.Element[S], vk VerifyingKey[G1El, G2El]) error { + + claimedValueG1 := v.ec.ScalarMulBase(&point) + + // [f(α) - f(a)]G₁ + fminusfaG1 := v.ec.Neg(claimedValueG1) + fminusfaG1 = v.ec.Add(fminusfaG1, &digest.G1El) + + // [-H(α)]G₁ + negQuotientPoly := v.ec.Neg(&proof.Quotient) + + // [f(α) - f(a) + a*H(α)]G₁ + totalG1 := v.ec.ScalarMul(&proof.Quotient, &point) + totalG1 = v.ec.Add(totalG1, fminusfaG1) + + // e([f(α)-f(a)+aH(α)]G₁], G₂).e([-H(α)]G₁, [α]G₂) == 1 + if err := v.pairing.PairingCheck( + []*G1El{totalG1, negQuotientPoly}, + []*G2El{&vk.G2[0], &vk.G2[1]}, + ); err != nil { + return fmt.Errorf("pairing check: %w", err) + } + return nil + +} + +func (v *Verifier[S, G1El, G2El, GTEl]) FoldProof(digests []Commitment[G1El], batchOpeningProof BatchOpeningProof[S, G1El], point emulated.Element[S], hf hash.FieldHasher, dataTranscript ...frontend.Variable) (OpeningProof[S, G1El], Commitment[G1El], error) { + + nbDigests := len(digests) + + // check consistency between numbers of claims vs number of digests + if nbDigests != len(batchOpeningProof.ClaimedValues) { + return OpeningProof[S, G1El]{}, Commitment[G1El]{}, ErrInvalidNbDigests + } + + // derive the challenge γ, binded to the point and the commitments + gamma, err := deriveGamma(point, digests, batchOpeningProof.ClaimedValues, hf, dataTranscript...) + if err != nil { + return OpeningProof[S, G1El]{}, Commitment[G1El]{}, err + } + + // fold the claimed values and digests + // gammai = [1,γ,γ²,..,γⁿ⁻¹] + gammai := make([]emulated.Element[S], nbDigests) + gammai[0] = emulated.ValueOf[S](1) + if nbDigests > 1 { + gammai[1] = gamma + } + for i := 2; i < nbDigests; i++ { + v.scalarApi.Mul(&gammai[i-1], &gamma) + } + + foldedDigests, foldedEvaluations := v.fold(digests, batchOpeningProof.ClaimedValues, gammai) + + // create the folded opening proof + var res OpeningProof[S, G1El] + res.ClaimedValue = foldedEvaluations + res.Quotient = batchOpeningProof.Quotient + + return res, foldedDigests, nil + +} + +func (v *Verifier[S, G1El, G2El, GTEl]) fold(digests []Commitment[G1El], fai, ci []emulated.Element[S]) (Commitment[G1El], emulated.Element[S]) { + + // length inconsistency between digests and evaluations should have been done before calling this function + nbDigests := len(digests) + + // fold the claimed values ∑ᵢcᵢf(aᵢ) + var foldedEvaluations, tmp emulated.Element[S] + foldedEvaluations = emulated.ValueOf[S](0) + for i := 0; i < nbDigests; i++ { + tmp = *v.scalarApi.Mul(&fai[i], &ci[i]) + foldedEvaluations = *v.scalarApi.Add(&foldedEvaluations, &tmp) + } + + // fold the digests ∑ᵢ[cᵢ]([fᵢ(α)]G₁) + var foldedDigests Commitment[G1El] + foldedDigests.G1El = *v.ec.ScalarMul(&digests[0].G1El, &ci[0]) + for i := 1; i < nbDigests; i++ { + tmp := *v.ec.ScalarMul(&digests[i].G1El, &ci[i]) + foldedDigests.G1El = *v.ec.Add(&tmp, &foldedDigests.G1El) + } + + // folding done + return foldedDigests, foldedEvaluations + +} + +func (v *Verifier[S, G1El, G2El, GTEl]) BatchVerifySinglePoint(digests []Commitment[G1El], batchOpeningProof BatchOpeningProof[S, G1El], point emulated.Element[S], hf hash.FieldHasher, vk VerifyingKey[G1El, G2El], dataTranscript ...frontend.Variable) error { + + // fold the proof + foldedProof, foldedDigest, err := v.FoldProof(digests, batchOpeningProof, point, hf, dataTranscript...) + if err != nil { + return err + } + + // verify the foldedProof against the foldedDigest + err = v.CheckOpeningProof(foldedDigest, foldedProof, point, vk) + + return err +} + +func (v *Verifier[S, G1El, G2El, GTEl]) BatchVerifyMultiPoints(digests []Commitment[G1El], proofs []OpeningProof[S, G1El], points []emulated.Element[S], vk VerifyingKey[G1El, G2El]) error { + + // check consistency nb proogs vs nb digests + if len(digests) != len(proofs) || len(digests) != len(points) { + return ErrInvalidNbDigests + } + + // len(digests) should be nonzero because of randomNumbers + if len(digests) == 0 { + return ErrZeroNbDigests + } + + // if only one digest, call Verify + if len(digests) == 1 { + return v.CheckOpeningProof(digests[0], proofs[0], points[0], vk) + } + + // sample random numbers λᵢ for sampling + randomNumbers := make([]emulated.Element[S], len(digests)) + randomNumbers[0] = emulated.ValueOf[S](1) + for i := 1; i < len(randomNumbers); i++ { + // TODO use real random numbers, follow the solidity smart contract to know which variables are used as seed + randomNumbers[i] = emulated.ValueOf[S](42) + } + + // fold the committed quotients compute ∑ᵢλᵢ[Hᵢ(α)]G₁ + var foldedQuotients G1El + quotients := make([]G1El, len(proofs)) + for i := 0; i < len(randomNumbers); i++ { + quotients[i] = proofs[i].Quotient + } + foldedQuotients = *v.ec.ScalarMul("ients[0], &randomNumbers[0]) + for i := 1; i < len(digests); i++ { + tmp := *v.ec.ScalarMul("ients[i], &randomNumbers[i]) + foldedQuotients = *v.ec.Add(&tmp, &foldedQuotients) + } + + // fold digests and evals + evals := make([]emulated.Element[S], len(digests)) + for i := 0; i < len(randomNumbers); i++ { + evals[i] = proofs[i].ClaimedValue + } + + // fold the digests: ∑ᵢλᵢ[f_i(α)]G₁ + // fold the evals : ∑ᵢλᵢfᵢ(aᵢ) + foldedDigests, foldedEvals := v.fold(digests, evals, randomNumbers) + + // compute commitment to folded Eval [∑ᵢλᵢfᵢ(aᵢ)]G₁ + foldedEvalsCommit := v.ec.ScalarMul(&vk.G1, &foldedEvals) + + // compute foldedDigests = ∑ᵢλᵢ[fᵢ(α)]G₁ - [∑ᵢλᵢfᵢ(aᵢ)]G₁ + // foldedDigests.Sub(&foldedDigests, &foldedEvalsCommit) + tmp := v.ec.Neg(foldedEvalsCommit) + foldedDigests.G1El = *v.ec.Add(&foldedDigests.G1El, tmp) + + // combien the points and the quotients using γᵢ + // ∑ᵢλᵢ[p_i]([Hᵢ(α)]G₁) + var foldedPointsQuotients G1El + for i := 0; i < len(randomNumbers); i++ { + randomNumbers[i] = *v.scalarApi.Mul(&randomNumbers[i], &points[i]) + } + foldedPointsQuotients = *v.ec.ScalarMul("ients[0], &points[0]) + for i := 1; i < len(digests); i++ { + tmp = v.ec.ScalarMul("ients[i], &points[i]) + foldedPointsQuotients = *v.ec.Add(&foldedPointsQuotients, tmp) + } + + // ∑ᵢλᵢ[f_i(α)]G₁ - [∑ᵢλᵢfᵢ(aᵢ)]G₁ + ∑ᵢλᵢ[p_i]([Hᵢ(α)]G₁) + // = [∑ᵢλᵢf_i(α) - ∑ᵢλᵢfᵢ(aᵢ) + ∑ᵢλᵢpᵢHᵢ(α)]G₁ + foldedDigests.G1El = *v.ec.Add(&foldedDigests.G1El, &foldedPointsQuotients) + + // -∑ᵢλᵢ[Qᵢ(α)]G₁ + // foldedQuotients.Neg(&foldedQuotients) + foldedQuotients = *v.ec.Neg(&foldedQuotients) + + // pairing check + err := v.pairing.PairingCheck( + []*G1El{&foldedDigests.G1El, &foldedQuotients}, + []*G2El{&vk.G2[0], &vk.G2[1]}, + ) + + return err +} + +// deriveGamma derives a challenge using Fiat Shamir to fold proofs. +func deriveGamma[S emulated.FieldParams, G1El any](point emulated.Element[S], digests []Commitment[G1El], claimedValues []emulated.Element[S], hf hash.FieldHasher, dataTranscript ...frontend.Variable) (emulated.Element[S], error) { + + // derive the challenge gamma, binded to the point and the commitments + // fs := fiatshamir.NewTranscript(hf, "gamma") + // if err := fs.Bind("gamma", point.Marshal()); err != nil { + // return fr.Element{}, err + // } + // for i := range digests { + // if err := fs.Bind("gamma", digests[i].Marshal()); err != nil { + // return fr.Element{}, err + // } + // } + // for i := range claimedValues { + // if err := fs.Bind("gamma", claimedValues[i].Marshal()); err != nil { + // return fr.Element{}, err + // } + // } + + // for i := 0; i < len(dataTranscript); i++ { + // if err := fs.Bind("gamma", dataTranscript[i]); err != nil { + // return fr.Element{}, err + // } + // } + + // gammaByte, err := fs.ComputeChallenge("gamma") + // if err != nil { + // return fr.Element{}, err + // } + // var gamma fr.Element + // gamma.SetBytes(gammaByte) + + return point, nil +} From addc4fd87802f1ef90a0a1a809c445fdcc6904ac Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Mon, 30 Oct 2023 17:24:55 +0100 Subject: [PATCH 02/15] feat: test kzg, error Modulus method missing --- std/commitments/kzg_refactor/conversion.go | 204 +++++++++ std/commitments/kzg_refactor/verifier_test.go | 397 ++++++++++++++++++ 2 files changed, 601 insertions(+) create mode 100644 std/commitments/kzg_refactor/conversion.go create mode 100644 std/commitments/kzg_refactor/verifier_test.go diff --git a/std/commitments/kzg_refactor/conversion.go b/std/commitments/kzg_refactor/conversion.go new file mode 100644 index 0000000000..5d5f4f1ee3 --- /dev/null +++ b/std/commitments/kzg_refactor/conversion.go @@ -0,0 +1,204 @@ +package kzg_refactor + +import ( + "fmt" + + fr_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" + fr_bw6761 "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + + bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377" + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315" + "github.com/consensys/gnark-crypto/ecc/bn254" + bw6761 "github.com/consensys/gnark-crypto/ecc/bw6-761" + + kzg_bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377/kzg" + kzg_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/kzg" + kzg_bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315/kzg" + kzg_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/kzg" + kzg_bw6761 "github.com/consensys/gnark-crypto/ecc/bw6-761/kzg" + + "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/math/emulated" +) + +// ValueOfScalar initializes a scalar in a witness from a native scalar (Fr) point. +// The scalars are always emulated. +func ValueOfScalar[S emulated.FieldParams](scalar any) (emulated.Element[S], error) { + var ret emulated.Element[S] + switch s := any(&ret).(type) { + case *emulated.Element[emulated.BN254Fr]: + tScalar, ok := scalar.(fr_bn254.Element) + if !ok { + return ret, fmt.Errorf("mismatching types %T %T", ret, tScalar) + } + *s = sw_bn254.NewScalar(tScalar) + case *emulated.Element[emulated.BW6761Fr]: + tScalar, ok := scalar.(fr_bw6761.Element) + if !ok { + return ret, fmt.Errorf("mismatching types %T %T", ret, tScalar) + } + *s = sw_bw6761.NewScalar(tScalar) + case *emulated.Element[emulated.BLS12381Fr]: + tScalar, ok := scalar.(fr_bls12381.Element) + if !ok { + return ret, fmt.Errorf("mismatching types %T %T", ret, tScalar) + } + *s = sw_bls12381.NewScalar(tScalar) + default: + return ret, fmt.Errorf("unknown type parametrization") + } + return ret, nil + +} + +// ValueOfCommitment initializes a KZG commitment witness from a native +// commitment. It returns an error if there is a conflict between the type +// parameters and provided native commitment type. +func ValueOfCommitment[G1El any](cmt any) (Commitment[G1El], error) { + var ret Commitment[G1El] + switch s := any(&ret).(type) { + case *Commitment[sw_bn254.G1Affine]: + tCmt, ok := cmt.(bn254.G1Affine) + if !ok { + return ret, fmt.Errorf("mismatching types %T %T", ret, cmt) + } + s.G1El = sw_bn254.NewG1Affine(tCmt) + case *Commitment[sw_bls12377.G1Affine]: + tCmt, ok := cmt.(bls12377.G1Affine) + if !ok { + return ret, fmt.Errorf("mismatching types %T %T", ret, cmt) + } + s.G1El = sw_bls12377.NewG1Affine(tCmt) + case *Commitment[sw_bls12381.G1Affine]: + tCmt, ok := cmt.(bls12381.G1Affine) + if !ok { + return ret, fmt.Errorf("mismatching types %T %T", ret, cmt) + } + s.G1El = sw_bls12381.NewG1Affine(tCmt) + case *Commitment[sw_bw6761.G1Affine]: + tCmt, ok := cmt.(bw6761.G1Affine) + if !ok { + return ret, fmt.Errorf("mismatching types %T %T", ret, cmt) + } + s.G1El = sw_bw6761.NewG1Affine(tCmt) + case *Commitment[sw_bls24315.G1Affine]: + tCmt, ok := cmt.(bls24315.G1Affine) + if !ok { + return ret, fmt.Errorf("mismatching types %T %T", ret, cmt) + } + s.G1El = sw_bls24315.NewG1Affine(tCmt) + default: + return ret, fmt.Errorf("unknown type parametrization") + } + return ret, nil +} + +// ValueOfOpeningProof initializes an opening proof from the given proof and +// point. It returns an error if there is a mismatch between the type parameters +// and types of the provided point and proof. +func ValueOfOpeningProof[S emulated.FieldParams, G1El any](proof any) (OpeningProof[S, G1El], error) { + var ret OpeningProof[S, G1El] + switch s := any(&ret).(type) { + case *OpeningProof[emulated.BN254Fr, sw_bn254.G1Affine]: + tProof, ok := proof.(kzg_bn254.OpeningProof) + if !ok { + return ret, fmt.Errorf("mismatching types %T %T", ret, proof) + } + s.Quotient = sw_bn254.NewG1Affine(tProof.H) + s.ClaimedValue = sw_bn254.NewScalar(tProof.ClaimedValue) + + // TODO implement BLS12377FR emulated + // case *OpeningProof[emulated.BLS12377FR, sw_bls12377.G1Affine]: + // tProof, ok := proof.(kzg_bls12377.OpeningProof) + // if !ok { + // return ret, fmt.Errorf("mismatching types %T %T", ret, proof) + // } + // s.Quotient = sw_bls12377.NewG1Affine(tProof.H) + // s.ClaimedValue = tProof.ClaimedValue.String() + case *OpeningProof[emulated.BLS12381Fr, sw_bls12381.G1Affine]: + tProof, ok := proof.(kzg_bls12381.OpeningProof) + if !ok { + return ret, fmt.Errorf("mismatching types %T %T", ret, proof) + } + s.Quotient = sw_bls12381.NewG1Affine(tProof.H) + s.ClaimedValue = sw_bls12381.NewScalar(tProof.ClaimedValue) + case *OpeningProof[emulated.BW6761Fr, sw_bw6761.G1Affine]: + tProof, ok := proof.(kzg_bw6761.OpeningProof) + if !ok { + return ret, fmt.Errorf("mismatching types %T %T", ret, proof) + } + s.Quotient = sw_bw6761.NewG1Affine(tProof.H) + s.ClaimedValue = sw_bw6761.NewScalar(tProof.ClaimedValue) + + // TODO implement BLS24315FR emulated + // case *OpeningProof[emulated.BLS24315, sw_bls24315.G1Affine]: + // tProof, ok := proof.(kzg_bls24315.OpeningProof) + // if !ok { + // return ret, fmt.Errorf("mismatching types %T %T", ret, proof) + // } + // s.Quotient = sw_bls24315.NewG1Affine(tProof.H) + // s.ClaimedValue = tProof.ClaimedValue.String() + + default: + return ret, fmt.Errorf("unknown type parametrization") + } + return ret, nil +} + +// ValueOfVerifyingKey initializes verifying key witness from the native +// verifying key. It returns an error if there is a mismatch between the type +// parameters and the provided verifying key type. +func ValueOfVerifyingKey[G1El, G2El any](vk any) (VerifyingKey[G1El, G2El], error) { + var ret VerifyingKey[G1El, G2El] + switch s := any(&ret).(type) { + case *VerifyingKey[sw_bn254.G1Affine, sw_bn254.G2Affine]: + tVk, ok := vk.(kzg_bn254.VerifyingKey) + if !ok { + return ret, fmt.Errorf("mismatching types %T %T", ret, vk) + } + s.G1 = sw_bn254.NewG1Affine(tVk.G1) + s.G2[0] = sw_bn254.NewG2Affine(tVk.G2[0]) + s.G2[1] = sw_bn254.NewG2Affine(tVk.G2[1]) + case *VerifyingKey[sw_bls12377.G1Affine, sw_bls12377.G2Affine]: + tVk, ok := vk.(kzg_bls12377.VerifyingKey) + if !ok { + return ret, fmt.Errorf("mismatching types %T %T", ret, vk) + } + s.G1 = sw_bls12377.NewG1Affine(tVk.G1) + s.G2[0] = sw_bls12377.NewG2Affine(tVk.G2[0]) + s.G2[1] = sw_bls12377.NewG2Affine(tVk.G2[1]) + case *VerifyingKey[sw_bls12381.G1Affine, sw_bls12381.G2Affine]: + tVk, ok := vk.(kzg_bls12381.VerifyingKey) + if !ok { + return ret, fmt.Errorf("mismatching types %T %T", ret, vk) + } + s.G1 = sw_bls12381.NewG1Affine(tVk.G1) + s.G2[0] = sw_bls12381.NewG2Affine(tVk.G2[0]) + s.G2[1] = sw_bls12381.NewG2Affine(tVk.G2[1]) + case *VerifyingKey[sw_bw6761.G1Affine, sw_bw6761.G2Affine]: + tVk, ok := vk.(kzg_bw6761.VerifyingKey) + if !ok { + return ret, fmt.Errorf("mismatching types %T %T", ret, vk) + } + s.G1 = sw_bw6761.NewG1Affine(tVk.G1) + s.G2[0] = sw_bw6761.NewG2Affine(tVk.G2[0]) + s.G2[1] = sw_bw6761.NewG2Affine(tVk.G2[1]) + case *VerifyingKey[sw_bls24315.G1Affine, sw_bls24315.G2Affine]: + tVk, ok := vk.(kzg_bls24315.VerifyingKey) + if !ok { + return ret, fmt.Errorf("mismatching types %T %T", ret, vk) + } + s.G1 = sw_bls24315.NewG1Affine(tVk.G1) + s.G2[0] = sw_bls24315.NewG2Affine(tVk.G2[0]) + s.G2[1] = sw_bls24315.NewG2Affine(tVk.G2[1]) + default: + return ret, fmt.Errorf("unknown type parametrization") + } + return ret, nil +} diff --git a/std/commitments/kzg_refactor/verifier_test.go b/std/commitments/kzg_refactor/verifier_test.go new file mode 100644 index 0000000000..4b697a478e --- /dev/null +++ b/std/commitments/kzg_refactor/verifier_test.go @@ -0,0 +1,397 @@ +package kzg_refactor + +import ( + "crypto/rand" + "fmt" + "testing" + + "github.com/consensys/gnark-crypto/ecc" + fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" + kzg_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/kzg" + "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/std/algebra/emulated/sw_bn254" + "github.com/consensys/gnark/std/math/emulated" + "github.com/consensys/gnark/test" +) + +const ( + kzgSize = 128 + polynomialSize = 100 +) + +type KZGVerificationCircuit[S emulated.FieldParams, G1El, G2El, GTEl any] struct { + Vk VerifyingKey[G1El, G2El] + Digest Commitment[G1El] + Proof OpeningProof[S, G1El] + Point emulated.Element[S] +} + +func (c *KZGVerificationCircuit[S, G1El, G2El, GTEl]) Define(api frontend.API) error { + _, err := NewVerifier[S, G1El, G2El, GTEl](api) + if err != nil { + return fmt.Errorf("get pairing: %w", err) + } + // if err := verifier.CheckOpeningProof(c.Digest, c.Proof, c.Point, c.Vk); err != nil { + // return fmt.Errorf("assert proof: %w", err) + // } + return nil +} + +func TestKZGVerificationEmulated(t *testing.T) { + assert := test.NewAssert(t) + + alpha, err := rand.Int(rand.Reader, ecc.BN254.ScalarField()) + assert.NoError(err) + srs, err := kzg_bn254.NewSRS(kzgSize, alpha) + assert.NoError(err) + + f := make([]fr_bn254.Element, polynomialSize) + for i := range f { + f[i].SetRandom() + } + + com, err := kzg_bn254.Commit(f, srs.Pk) + assert.NoError(err) + + var point fr_bn254.Element + point.SetRandom() + proof, err := kzg_bn254.Open(f, point, srs.Pk) + assert.NoError(err) + + if err = kzg_bn254.Verify(&com, &proof, point, srs.Vk); err != nil { + t.Fatal("verify proof", err) + } + + wCmt, err := ValueOfCommitment[sw_bn254.G1Affine](com) + assert.NoError(err) + wProof, err := ValueOfOpeningProof[emulated.BN254Fr, sw_bn254.G1Affine](proof) + assert.NoError(err) + wVk, err := ValueOfVerifyingKey[sw_bn254.G1Affine, sw_bn254.G2Affine](srs.Vk) + assert.NoError(err) + + // wPoint, err := ValueOfScalar[emulated.BN254Fr](point) + wPoint, err := ValueOfScalar[emulated.BN254Fr](point) + assert.NoError(err) + + _ = KZGVerificationCircuit[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ + Vk: wVk, + Digest: wCmt, + Proof: wProof, + Point: wPoint, + } + // assert.CheckCircuit(&KZGVerificationCircuit[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{}, test.WithValidAssignment(&assignment)) +} + +// func TestKZGVerificationEmulated2(t *testing.T) { +// assert := test.NewAssert(t) + +// alpha, err := rand.Int(rand.Reader, ecc.BLS12_381.ScalarField()) +// assert.NoError(err) +// srs, err := kzg_bls12381.NewSRS(kzgSize, alpha) +// assert.NoError(err) + +// f := make([]fr_bls12381.Element, polynomialSize) +// for i := range f { +// f[i].SetRandom() +// } + +// com, err := kzg_bls12381.Commit(f, srs.Pk) +// assert.NoError(err) + +// var point fr_bls12381.Element +// point.SetRandom() +// proof, err := kzg_bls12381.Open(f, point, srs.Pk) +// assert.NoError(err) + +// if err = kzg_bls12381.Verify(&com, &proof, point, srs.Vk); err != nil { +// t.Fatal("verify proof", err) +// } + +// wCmt, err := ValueOfCommitment[sw_bls12381.G1Affine](com) +// assert.NoError(err) +// wProof, err := ValueOfOpeningProof[sw_bls12381.Scalar, sw_bls12381.G1Affine](point, proof) +// assert.NoError(err) +// wVk, err := ValueOfVerifyingKey[sw_bls12381.G2Affine](srs.Vk) +// assert.NoError(err) + +// assignment := KZGVerificationCircuit[sw_bls12381.Scalar, sw_bls12381.G1Affine, sw_bls12381.G2Affine, sw_bls12381.GTEl]{ +// VerifyingKey: wVk, +// Commitment: wCmt, +// OpeningProof: wProof, +// } +// assert.CheckCircuit(&KZGVerificationCircuit[sw_bls12381.Scalar, sw_bls12381.G1Affine, sw_bls12381.G2Affine, sw_bls12381.GTEl]{}, test.WithValidAssignment(&assignment)) +// } + +// func TestKZGVerificationEmulated3(t *testing.T) { +// assert := test.NewAssert(t) + +// alpha, err := rand.Int(rand.Reader, ecc.BW6_761.ScalarField()) +// assert.NoError(err) +// srs, err := kzg_bw6761.NewSRS(kzgSize, alpha) +// assert.NoError(err) + +// f := make([]fr_bw6761.Element, polynomialSize) +// for i := range f { +// f[i].SetRandom() +// } + +// com, err := kzg_bw6761.Commit(f, srs.Pk) +// assert.NoError(err) + +// var point fr_bw6761.Element +// point.SetRandom() +// proof, err := kzg_bw6761.Open(f, point, srs.Pk) +// assert.NoError(err) + +// if err = kzg_bw6761.Verify(&com, &proof, point, srs.Vk); err != nil { +// t.Fatal("verify proof", err) +// } + +// wCmt, err := ValueOfCommitment[sw_bw6761.G1Affine](com) +// assert.NoError(err) +// wProof, err := ValueOfOpeningProof[sw_bw6761.Scalar, sw_bw6761.G1Affine](point, proof) +// assert.NoError(err) +// wVk, err := ValueOfVerifyingKey[sw_bw6761.G2Affine](srs.Vk) +// assert.NoError(err) + +// assignment := KZGVerificationCircuit[sw_bw6761.Scalar, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{ +// VerifyingKey: wVk, +// Commitment: wCmt, +// OpeningProof: wProof, +// } +// assert.CheckCircuit(&KZGVerificationCircuit[sw_bw6761.Scalar, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{}, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BN254)) +// } + +// func TestKZGVerificationTwoChain(t *testing.T) { +// assert := test.NewAssert(t) + +// alpha, err := rand.Int(rand.Reader, ecc.BLS12_377.ScalarField()) +// assert.NoError(err) +// srs, err := kzg_bls12377.NewSRS(kzgSize, alpha) +// assert.NoError(err) + +// f := make([]fr_bls12377.Element, polynomialSize) +// for i := range f { +// f[i].SetRandom() +// } + +// com, err := kzg_bls12377.Commit(f, srs.Pk) +// assert.NoError(err) + +// var point fr_bls12377.Element +// point.SetRandom() +// proof, err := kzg_bls12377.Open(f, point, srs.Pk) +// assert.NoError(err) + +// if err = kzg_bls12377.Verify(&com, &proof, point, srs.Vk); err != nil { +// t.Fatal("verify proof", err) +// } + +// wCmt, err := ValueOfCommitment[sw_bls12377.G1Affine](com) +// assert.NoError(err) +// wProof, err := ValueOfOpeningProof[sw_bls12377.Scalar, sw_bls12377.G1Affine](point, proof) +// assert.NoError(err) +// wVk, err := ValueOfVerifyingKey[sw_bls12377.G2Affine](srs.Vk) +// assert.NoError(err) + +// assignment := KZGVerificationCircuit[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ +// VerifyingKey: wVk, +// Commitment: wCmt, +// OpeningProof: wProof, +// } + +// assert.CheckCircuit(&KZGVerificationCircuit[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{}, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BW6_761)) +// } + +// func TestKZGVerificationTwoChain2(t *testing.T) { +// assert := test.NewAssert(t) + +// alpha, err := rand.Int(rand.Reader, ecc.BLS24_315.ScalarField()) +// assert.NoError(err) +// srs, err := kzg_bls24315.NewSRS(kzgSize, alpha) +// assert.NoError(err) + +// f := make([]fr_bls24315.Element, polynomialSize) +// for i := range f { +// f[i].SetRandom() +// } + +// com, err := kzg_bls24315.Commit(f, srs.Pk) +// assert.NoError(err) + +// var point fr_bls24315.Element +// point.SetRandom() +// proof, err := kzg_bls24315.Open(f, point, srs.Pk) +// assert.NoError(err) + +// if err = kzg_bls24315.Verify(&com, &proof, point, srs.Vk); err != nil { +// t.Fatal("verify proof", err) +// } + +// wCmt, err := ValueOfCommitment[sw_bls24315.G1Affine](com) +// assert.NoError(err) +// wProof, err := ValueOfOpeningProof[sw_bls24315.Scalar, sw_bls24315.G1Affine](point, proof) +// assert.NoError(err) +// wVk, err := ValueOfVerifyingKey[sw_bls24315.G2Affine](srs.Vk) +// assert.NoError(err) + +// assignment := KZGVerificationCircuit[sw_bls24315.Scalar, sw_bls24315.G1Affine, sw_bls24315.G2Affine, sw_bls24315.GT]{ +// VerifyingKey: wVk, +// Commitment: wCmt, +// OpeningProof: wProof, +// } + +// assert.CheckCircuit(&KZGVerificationCircuit[sw_bls24315.Scalar, sw_bls24315.G1Affine, sw_bls24315.G2Affine, sw_bls24315.GT]{}, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BW6_633)) +// } + +// func TestValueOfCommitment(t *testing.T) { +// assert := test.NewAssert(t) +// assert.Run(func(assert *test.Assert) { +// _, _, G1, _ := bn254.Generators() +// assignment, err := ValueOfCommitment[sw_bn254.G1Affine](G1) +// assert.NoError(err) +// _ = assignment +// }, "bn254") +// assert.Run(func(assert *test.Assert) { +// _, _, G1, _ := bls12377.Generators() +// assignment, err := ValueOfCommitment[sw_bls12377.G1Affine](G1) +// assert.NoError(err) +// _ = assignment +// }, "bls12377") +// assert.Run(func(assert *test.Assert) { +// _, _, G1, _ := bls12381.Generators() +// assignment, err := ValueOfCommitment[sw_bls12381.G1Affine](G1) +// assert.NoError(err) +// _ = assignment +// }, "bls12381") +// assert.Run(func(assert *test.Assert) { +// _, _, G1, _ := bw6761.Generators() +// assignment, err := ValueOfCommitment[sw_bw6761.G1Affine](G1) +// assert.NoError(err) +// _ = assignment +// }, "bw6761") +// assert.Run(func(assert *test.Assert) { +// _, _, G1, _ := bls24315.Generators() +// assignment, err := ValueOfCommitment[sw_bls24315.G1Affine](G1) +// assert.NoError(err) +// _ = assignment +// }, "bls24315") +// } + +// func TestValueOfOpeningProof(t *testing.T) { +// assert := test.NewAssert(t) +// assert.Run(func(assert *test.Assert) { +// _, _, G1, _ := bn254.Generators() +// var value, point fr_bn254.Element +// value.SetRandom() +// point.SetRandom() +// proof := kzg_bn254.OpeningProof{ +// H: G1, +// ClaimedValue: value, +// } +// assignment, err := ValueOfOpeningProof[sw_bn254.Scalar, sw_bn254.G1Affine](point, proof) +// assert.NoError(err) +// _ = assignment +// }, "bn254") +// assert.Run(func(assert *test.Assert) { +// _, _, G1, _ := bls12377.Generators() +// var value, point fr_bls12377.Element +// value.SetRandom() +// point.SetRandom() +// proof := kzg_bls12377.OpeningProof{ +// H: G1, +// ClaimedValue: value, +// } +// assignment, err := ValueOfOpeningProof[sw_bls12377.Scalar, sw_bls12377.G1Affine](point, proof) +// assert.NoError(err) +// _ = assignment +// }, "bls12377") +// assert.Run(func(assert *test.Assert) { +// _, _, G1, _ := bls12381.Generators() +// var value, point fr_bls12381.Element +// value.SetRandom() +// point.SetRandom() +// proof := kzg_bls12381.OpeningProof{ +// H: G1, +// ClaimedValue: value, +// } +// assignment, err := ValueOfOpeningProof[sw_bls12381.Scalar, sw_bls12381.G1Affine](point, proof) +// assert.NoError(err) +// _ = assignment +// }, "bls12381") +// assert.Run(func(assert *test.Assert) { +// _, _, G1, _ := bw6761.Generators() +// var value, point fr_bw6761.Element +// value.SetRandom() +// point.SetRandom() +// proof := kzg_bw6761.OpeningProof{ +// H: G1, +// ClaimedValue: value, +// } +// assignment, err := ValueOfOpeningProof[sw_bw6761.Scalar, sw_bw6761.G1Affine](point, proof) +// assert.NoError(err) +// _ = assignment +// }, "bw6761") +// assert.Run(func(assert *test.Assert) { +// _, _, G1, _ := bls24315.Generators() +// var value, point fr_bls24315.Element +// value.SetRandom() +// point.SetRandom() +// proof := kzg_bls24315.OpeningProof{ +// H: G1, +// ClaimedValue: value, +// } +// assignment, err := ValueOfOpeningProof[sw_bls24315.Scalar, sw_bls24315.G1Affine](point, proof) +// assert.NoError(err) +// _ = assignment +// }, "bls24315") +// } + +// func TestValueOfSRS(t *testing.T) { +// assert := test.NewAssert(t) +// assert.Run(func(assert *test.Assert) { +// _, _, _, G2 := bn254.Generators() +// vk := kzg_bn254.VerifyingKey{ +// G2: [2]bn254.G2Affine{G2, G2}, +// } +// assignment, err := ValueOfVerifyingKey[sw_bn254.G2Affine](vk) +// assert.NoError(err) +// _ = assignment +// }, "bn254") +// assert.Run(func(assert *test.Assert) { +// _, _, _, G2 := bls12377.Generators() +// vk := kzg_bls12377.VerifyingKey{ +// G2: [2]bls12377.G2Affine{G2, G2}, +// } +// assignment, err := ValueOfVerifyingKey[sw_bls12377.G2Affine](vk) +// assert.NoError(err) +// _ = assignment +// }, "bls12377") +// assert.Run(func(assert *test.Assert) { +// _, _, _, G2 := bls12381.Generators() +// vk := kzg_bls12381.VerifyingKey{ +// G2: [2]bls12381.G2Affine{G2, G2}, +// } +// assignment, err := ValueOfVerifyingKey[sw_bls12381.G2Affine](vk) +// assert.NoError(err) +// _ = assignment +// }, "bls12381") +// assert.Run(func(assert *test.Assert) { +// _, _, _, G2 := bw6761.Generators() +// vk := kzg_bw6761.VerifyingKey{ +// G2: [2]bw6761.G2Affine{G2, G2}, +// } +// assignment, err := ValueOfVerifyingKey[sw_bw6761.G2Affine](vk) +// assert.NoError(err) +// _ = assignment +// }, "bw6761") +// assert.Run(func(assert *test.Assert) { +// _, _, _, G2 := bls24315.Generators() +// vk := kzg_bls24315.VerifyingKey{ +// G2: [2]bls24315.G2Affine{G2, G2}, +// } +// assignment, err := ValueOfVerifyingKey[sw_bls24315.G2Affine](vk) +// assert.NoError(err) +// _ = assignment +// }, "bls24315") +// } From 05ff3c59eed717f2955a545a62a23a99a9fe4914 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Tue, 31 Oct 2023 23:07:22 +0100 Subject: [PATCH 03/15] feat: opening single point ok --- std/commitments/kzg_refactor/verifier.go | 2 +- std/commitments/kzg_refactor/verifier_test.go | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/std/commitments/kzg_refactor/verifier.go b/std/commitments/kzg_refactor/verifier.go index ae0995ca32..a6b1327426 100644 --- a/std/commitments/kzg_refactor/verifier.go +++ b/std/commitments/kzg_refactor/verifier.go @@ -80,7 +80,7 @@ func NewVerifier[S emulated.FieldParams, G1El, G2El, GtEl any](api frontend.API) // S here is emulated.FieldParams func (v *Verifier[S, G1El, G2El, GTEl]) CheckOpeningProof(digest Commitment[G1El], proof OpeningProof[S, G1El], point emulated.Element[S], vk VerifyingKey[G1El, G2El]) error { - claimedValueG1 := v.ec.ScalarMulBase(&point) + claimedValueG1 := v.ec.ScalarMulBase(&proof.ClaimedValue) // [f(α) - f(a)]G₁ fminusfaG1 := v.ec.Neg(claimedValueG1) diff --git a/std/commitments/kzg_refactor/verifier_test.go b/std/commitments/kzg_refactor/verifier_test.go index 4b697a478e..41d3552ead 100644 --- a/std/commitments/kzg_refactor/verifier_test.go +++ b/std/commitments/kzg_refactor/verifier_test.go @@ -8,6 +8,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" kzg_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/kzg" + "github.com/consensys/gnark/backend" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra/emulated/sw_bn254" "github.com/consensys/gnark/std/math/emulated" @@ -27,13 +28,13 @@ type KZGVerificationCircuit[S emulated.FieldParams, G1El, G2El, GTEl any] struct } func (c *KZGVerificationCircuit[S, G1El, G2El, GTEl]) Define(api frontend.API) error { - _, err := NewVerifier[S, G1El, G2El, GTEl](api) + verifier, err := NewVerifier[S, G1El, G2El, GTEl](api) if err != nil { return fmt.Errorf("get pairing: %w", err) } - // if err := verifier.CheckOpeningProof(c.Digest, c.Proof, c.Point, c.Vk); err != nil { - // return fmt.Errorf("assert proof: %w", err) - // } + if err := verifier.CheckOpeningProof(c.Digest, c.Proof, c.Point, c.Vk); err != nil { + return fmt.Errorf("assert proof: %w", err) + } return nil } @@ -73,13 +74,13 @@ func TestKZGVerificationEmulated(t *testing.T) { wPoint, err := ValueOfScalar[emulated.BN254Fr](point) assert.NoError(err) - _ = KZGVerificationCircuit[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ + assignment := KZGVerificationCircuit[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ Vk: wVk, Digest: wCmt, Proof: wProof, Point: wPoint, } - // assert.CheckCircuit(&KZGVerificationCircuit[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{}, test.WithValidAssignment(&assignment)) + assert.CheckCircuit(&KZGVerificationCircuit[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{}, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) } // func TestKZGVerificationEmulated2(t *testing.T) { From 2184377adede430be1d4493f1ccc8b8f4bf896e9 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Thu, 2 Nov 2023 18:07:13 +0100 Subject: [PATCH 04/15] feat: WriteString method on wrapped hash --- std/recursion/wrapped_hash.go | 92 +++++++++++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 5 deletions(-) diff --git a/std/recursion/wrapped_hash.go b/std/recursion/wrapped_hash.go index 1565608576..8ed9ec2645 100644 --- a/std/recursion/wrapped_hash.go +++ b/std/recursion/wrapped_hash.go @@ -13,6 +13,15 @@ import ( "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/std/math/bits" "golang.org/x/exp/slices" + + bls12_377 "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + bls12_381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + bls24_315 "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" + bls24_317 "github.com/consensys/gnark-crypto/ecc/bls24-317/fr" + bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" + bw6_633 "github.com/consensys/gnark-crypto/ecc/bw6-633/fr" + bw6_756 "github.com/consensys/gnark-crypto/ecc/bw6-756/fr" + bw6_761 "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" ) type shortNativeHash struct { @@ -20,9 +29,9 @@ type shortNativeHash struct { outSize int bitBlockSize int - - ringBuf *bytes.Buffer - buf []byte + ecID ecc.ID + ringBuf *bytes.Buffer + buf []byte } // NewShort returns a native hash function which reads elements in the current native @@ -32,34 +41,44 @@ type shortNativeHash struct { func NewShort(current, target *big.Int) (hash.Hash, error) { var h cryptomimc.Hash var bitBlockSize int + var ecid ecc.ID switch current.String() { case ecc.BN254.ScalarField().String(): h = cryptomimc.MIMC_BN254 bitBlockSize = ecc.BN254.ScalarField().BitLen() + ecid = ecc.BN254 case ecc.BLS12_381.ScalarField().String(): h = cryptomimc.MIMC_BLS12_381 bitBlockSize = ecc.BLS12_381.ScalarField().BitLen() + ecid = ecc.BLS12_381 case ecc.BLS12_377.ScalarField().String(): h = cryptomimc.MIMC_BLS12_377 bitBlockSize = ecc.BLS12_377.ScalarField().BitLen() + ecid = ecc.BLS12_377 case ecc.BLS12_378.ScalarField().String(): h = cryptomimc.MIMC_BLS12_378 bitBlockSize = ecc.BLS12_378.ScalarField().BitLen() + ecid = ecc.BLS12_378 case ecc.BW6_761.ScalarField().String(): h = cryptomimc.MIMC_BW6_761 bitBlockSize = ecc.BW6_761.ScalarField().BitLen() + ecid = ecc.BW6_761 case ecc.BLS24_315.ScalarField().String(): h = cryptomimc.MIMC_BLS24_315 bitBlockSize = ecc.BLS24_315.ScalarField().BitLen() + ecid = ecc.BLS24_315 case ecc.BLS24_317.ScalarField().String(): h = cryptomimc.MIMC_BLS24_317 bitBlockSize = ecc.BLS24_317.ScalarField().BitLen() + ecid = ecc.BLS24_317 case ecc.BW6_633.ScalarField().String(): h = cryptomimc.MIMC_BW6_633 bitBlockSize = ecc.BW6_633.ScalarField().BitLen() + ecid = ecc.BW6_633 case ecc.BW6_756.ScalarField().String(): h = cryptomimc.MIMC_BW6_756 bitBlockSize = ecc.BW6_756.ScalarField().BitLen() + ecid = ecc.BW6_756 default: return nil, fmt.Errorf("no default mimc for scalar field: %s", current.String()) } @@ -71,10 +90,10 @@ func NewShort(current, target *big.Int) (hash.Hash, error) { if nbBits > current.BitLen() { nbBits = current.BitLen() } - return newShortFromParam(hh, bitBlockSize, nbBits), nil + return newShortFromParam(hh, ecid, bitBlockSize, nbBits), nil } -func newShortFromParam(hf hash.Hash, bitBlockSize, outSize int) hash.Hash { +func newShortFromParam(hf hash.Hash, ecid ecc.ID, bitBlockSize, outSize int) hash.Hash { // TODO: right now assume bitLength is the modulus bit length. We subtract within return &shortNativeHash{ @@ -82,6 +101,7 @@ func newShortFromParam(hf hash.Hash, bitBlockSize, outSize int) hash.Hash { outSize: outSize, bitBlockSize: bitBlockSize, buf: make([]byte, (bitBlockSize+7)/8), + ecID: ecid, ringBuf: new(bytes.Buffer), } } @@ -128,6 +148,68 @@ func (h *shortNativeHash) Size() int { return (int(h.outSize) + 6) / 8 } +func (h *shortNativeHash) WriteString(rawBytes []byte) { + dst := []byte("string:") + switch h.ecID { + case ecc.BN254: + if x, err := bn254.Hash(rawBytes, dst, 1); err == nil { + bx := x[0].Bytes() + h.Write(bx[:]) + } else { + panic(err) + } + case ecc.BLS12_381: + if x, err := bls12_381.Hash(rawBytes, dst, 1); err == nil { + bx := x[0].Bytes() + h.Write(bx[:]) + } else { + panic(err) + } + case ecc.BLS12_377: + if x, err := bls12_377.Hash(rawBytes, dst, 1); err == nil { + bx := x[0].Bytes() + h.Write(bx[:]) + } else { + panic(err) + } + case ecc.BW6_761: + if x, err := bw6_761.Hash(rawBytes, dst, 1); err == nil { + bx := x[0].Bytes() + h.Write(bx[:]) + } else { + panic(err) + } + case ecc.BLS24_315: + if x, err := bls24_315.Hash(rawBytes, dst, 1); err == nil { + bx := x[0].Bytes() + h.Write(bx[:]) + } else { + panic(err) + } + case ecc.BLS24_317: + if x, err := bls24_317.Hash(rawBytes, dst, 1); err == nil { + bx := x[0].Bytes() + h.Write(bx[:]) + } else { + panic(err) + } + case ecc.BW6_633: + if x, err := bw6_633.Hash(rawBytes, dst, 1); err == nil { + bx := x[0].Bytes() + h.Write(bx[:]) + } else { + panic(err) + } + case ecc.BW6_756: + if x, err := bw6_756.Hash(rawBytes, dst, 1); err == nil { + bx := x[0].Bytes() + h.Write(bx[:]) + } else { + panic(err) + } + } +} + func (h *shortNativeHash) BlockSize() int { return h.wrapped.BlockSize() } From 0206f022b97583aaf85710f92584255718a1c21b Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Thu, 2 Nov 2023 19:25:59 +0100 Subject: [PATCH 05/15] feat: test FS bitmode gadget ok (more tests to add...) --- std/fiat-shamir/transcript.go | 15 +++++- std/fiat-shamir/transcript_test.go | 87 ++++++++++++++++++++++++++++-- std/recursion/wrapped_hash_test.go | 4 +- 3 files changed, 99 insertions(+), 7 deletions(-) diff --git a/std/fiat-shamir/transcript.go b/std/fiat-shamir/transcript.go index 63fe8e786d..8d507052e9 100644 --- a/std/fiat-shamir/transcript.go +++ b/std/fiat-shamir/transcript.go @@ -22,6 +22,7 @@ import ( "github.com/consensys/gnark/constant" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/hash" + "golang.org/x/exp/slices" ) // errChallengeNotFound is returned when a wrong challenge name is provided. @@ -94,7 +95,9 @@ func (t *Transcript) Bind(challengeID string, values []frontend.Variable) error // The resulting variable is: // * H(name ∥ previous_challenge ∥ binded_values...) if the challenge is not the first one // * H(name ∥ binded_values... ) if it's is the first challenge -func (t *Transcript) ComputeChallenge(challengeID string) (frontend.Variable, error) { +// If bitMode == true, the data binded to a challenge is supposed to consist of bits, that +// is when Bind(challengeID, values) is called, values is supposed to be a slice of bits. +func (t *Transcript) ComputeChallenge(challengeID string, bitMod bool) (frontend.Variable, error) { challenge, ok := t.challenges[challengeID] @@ -112,7 +115,15 @@ func (t *Transcript) ComputeChallenge(challengeID string) (frontend.Variable, er // write the challenge name, the purpose is to have a domain separator cChallenge := []byte(challengeID) // if we send a string, it is assumed to be a base10 number if challengeName, err := constant.HashedBytes(t.api, cChallenge); err == nil { - t.h.Write(challengeName) + if bitMod { + nbBits := 8 * ((t.api.Compiler().Field().BitLen() + 7) / 8) + // TODO waste of constraints, should to the binary decomposition in bigInt directly + binChallengeName := t.api.ToBinary(challengeName, nbBits) + slices.Reverse(binChallengeName) + t.h.Write(binChallengeName...) + } else { + t.h.Write(challengeName) + } } else { return nil, err } diff --git a/std/fiat-shamir/transcript_test.go b/std/fiat-shamir/transcript_test.go index 5a30f7eb3c..381b08a23c 100644 --- a/std/fiat-shamir/transcript_test.go +++ b/std/fiat-shamir/transcript_test.go @@ -28,9 +28,13 @@ import ( "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/internal/utils" "github.com/consensys/gnark/std/hash/mimc" + "github.com/consensys/gnark/std/recursion" "github.com/consensys/gnark/test" ) +//------------------------------------------------------ +// bitMode==false + type FiatShamirCircuit struct { Bindings [3][4]frontend.Variable `gnark:",public"` Challenges [3]frontend.Variable `gnark:",secret"` @@ -60,16 +64,16 @@ func (circuit *FiatShamirCircuit) Define(api frontend.API) error { // derive challenges var challenges [3]frontend.Variable - challenges[0], err = tsSnark.ComputeChallenge("alpha") + challenges[0], err = tsSnark.ComputeChallenge("alpha", false) if err != nil { return err } - challenges[1], err = tsSnark.ComputeChallenge("beta") + challenges[1], err = tsSnark.ComputeChallenge("beta", false) if err != nil { return err } - challenges[2], err = tsSnark.ComputeChallenge("gamma") + challenges[2], err = tsSnark.ComputeChallenge("gamma", false) if err != nil { return err } @@ -142,6 +146,83 @@ func TestFiatShamir(t *testing.T) { } +//------------------------------------------------------ +// bitMode==true + +type FiatShamirCircuitBitMode struct { + // Bindings [3][4]frontend.Variable `gnark:",public"` + Challenges frontend.Variable +} + +func (circuit *FiatShamirCircuitBitMode) Define(api frontend.API) error { + + // pick a number on byte shorter than the modulus size + var target big.Int + target.SetUint64(1) + nbBits := api.Compiler().Field().BitLen() + nn := ((nbBits+7)/8)*8 - 8 + target.Lsh(&target, uint(nn)) + + // create the wrapped hash function + whSnark, err := recursion.NewHash(api, &target, true) + if err != nil { + return err + } + + // New transcript with 3 challenges to be derived + tsSnark := NewTranscript(api, whSnark, "alpha") + + challenge, err := tsSnark.ComputeChallenge("alpha", true) + if err != nil { + return err + } + + api.AssertIsEqual(challenge, circuit.Challenges) + + return nil +} + +func TestFiatShamirBitMode(t *testing.T) { + + assert := test.NewAssert(t) + + testData := map[ecc.ID]hash.Hash{ + ecc.BN254: hash.MIMC_BN254, + // ecc.BLS12_377: hash.MIMC_BLS12_377, + // ecc.BLS12_381: hash.MIMC_BLS12_381, + // ecc.BLS24_315: hash.MIMC_BLS24_315, + // ecc.BLS24_317: hash.MIMC_BLS24_317, + // ecc.BW6_761: hash.MIMC_BW6_761, + // ecc.BW6_633: hash.MIMC_BW6_633, + } + + // compute the witness for each curve + for curveID, _ := range testData { + + // instantiate the hash and the transcript in plain go + nbBits := ((curveID.ScalarField().BitLen()+7)/8)*8 - 8 + target := big.NewInt(1) + target.Lsh(target, uint(nbBits)) + wh, err := recursion.NewShort(curveID.ScalarField(), target) + assert.NoError(err) + + ts := fiatshamir.NewTranscript(wh, "alpha") + + expectedChallenges, err := ts.ComputeChallenge("alpha") + assert.NoError(err) + + // instantiate the circuit with provided inputs + var witness FiatShamirCircuitBitMode + witness.Challenges = expectedChallenges + + assert.CheckCircuit(&FiatShamirCircuitBitMode{}, test.WithValidAssignment(&witness), test.WithCurves(curveID)) + } + +} + +//------------------------------------------------------ +// benchmark + func BenchmarkCompile(b *testing.B) { // create an empty cs var circuit FiatShamirCircuit diff --git a/std/recursion/wrapped_hash_test.go b/std/recursion/wrapped_hash_test.go index f26ec318d1..24ad55eb5e 100644 --- a/std/recursion/wrapped_hash_test.go +++ b/std/recursion/wrapped_hash_test.go @@ -104,8 +104,8 @@ func (c *hashMarshalG1Circuit[S, G1El]) Define(api frontend.API) error { if err != nil { return fmt.Errorf("get curve: %w", err) } - marshlled := curve.MarshalG1(c.Point) - h.Write(marshlled...) + marshalled := curve.MarshalG1(c.Point) + h.Write(marshalled...) res := h.Sum() api.AssertIsEqual(res, c.Expected) return nil From 9b4b1d4b241559db957ae0f59ff0175a12ecbbbb Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Thu, 2 Nov 2023 23:58:10 +0100 Subject: [PATCH 06/15] fix: gadget transcript with short hash ok --- std/commitments/fri/fri.go | 4 +- std/commitments/kzg_refactor/verifier_test.go | 321 +----------------- std/fiat-shamir/transcript.go | 9 +- std/fiat-shamir/transcript_test.go | 73 +++- std/gkr/gkr.go | 5 +- std/sumcheck/sumcheck.go | 5 +- 6 files changed, 93 insertions(+), 324 deletions(-) diff --git a/std/commitments/fri/fri.go b/std/commitments/fri/fri.go index 93dd0b301f..641f764f85 100644 --- a/std/commitments/fri/fri.go +++ b/std/commitments/fri/fri.go @@ -113,7 +113,7 @@ func (s RadixTwoFri) verifyProofOfProximitySingleRound(api frontend.API, salt fr if err != nil { return err } - xi[i], err = fs.ComputeChallenge(xis[i]) + xi[i], err = fs.ComputeChallenge(xis[i], false) if err != nil { return err } @@ -126,7 +126,7 @@ func (s RadixTwoFri) verifyProofOfProximitySingleRound(api frontend.API, salt fr if err != nil { return err } - binSeed, err := fs.ComputeChallenge(xis[s.nbSteps]) + binSeed, err := fs.ComputeChallenge(xis[s.nbSteps], false) if err != nil { return err } diff --git a/std/commitments/kzg_refactor/verifier_test.go b/std/commitments/kzg_refactor/verifier_test.go index 41d3552ead..ccd42b81bd 100644 --- a/std/commitments/kzg_refactor/verifier_test.go +++ b/std/commitments/kzg_refactor/verifier_test.go @@ -20,6 +20,9 @@ const ( polynomialSize = 100 ) +//-------------------------------------------------------- +// Single opening single point + type KZGVerificationCircuit[S emulated.FieldParams, G1El, G2El, GTEl any] struct { Vk VerifyingKey[G1El, G2El] Digest Commitment[G1El] @@ -83,316 +86,22 @@ func TestKZGVerificationEmulated(t *testing.T) { assert.CheckCircuit(&KZGVerificationCircuit[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{}, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) } -// func TestKZGVerificationEmulated2(t *testing.T) { -// assert := test.NewAssert(t) - -// alpha, err := rand.Int(rand.Reader, ecc.BLS12_381.ScalarField()) -// assert.NoError(err) -// srs, err := kzg_bls12381.NewSRS(kzgSize, alpha) -// assert.NoError(err) - -// f := make([]fr_bls12381.Element, polynomialSize) -// for i := range f { -// f[i].SetRandom() -// } +//-------------------------------------------------------- +// Fold proof -// com, err := kzg_bls12381.Commit(f, srs.Pk) -// assert.NoError(err) - -// var point fr_bls12381.Element -// point.SetRandom() -// proof, err := kzg_bls12381.Open(f, point, srs.Pk) -// assert.NoError(err) - -// if err = kzg_bls12381.Verify(&com, &proof, point, srs.Vk); err != nil { -// t.Fatal("verify proof", err) -// } - -// wCmt, err := ValueOfCommitment[sw_bls12381.G1Affine](com) -// assert.NoError(err) -// wProof, err := ValueOfOpeningProof[sw_bls12381.Scalar, sw_bls12381.G1Affine](point, proof) -// assert.NoError(err) -// wVk, err := ValueOfVerifyingKey[sw_bls12381.G2Affine](srs.Vk) -// assert.NoError(err) - -// assignment := KZGVerificationCircuit[sw_bls12381.Scalar, sw_bls12381.G1Affine, sw_bls12381.G2Affine, sw_bls12381.GTEl]{ -// VerifyingKey: wVk, -// Commitment: wCmt, -// OpeningProof: wProof, -// } -// assert.CheckCircuit(&KZGVerificationCircuit[sw_bls12381.Scalar, sw_bls12381.G1Affine, sw_bls12381.G2Affine, sw_bls12381.GTEl]{}, test.WithValidAssignment(&assignment)) +// type TestFoldProof[S emulated.FieldParams, G1El, G2El, GTEl any] struct { +// Vk VerifyingKey[G1El, G2El] +// Point emulated.Element[S] +// Digests [10]Commitment[G1El] +// BatchOpeningProof OpeningProof[S, G1El] // } -// func TestKZGVerificationEmulated3(t *testing.T) { -// assert := test.NewAssert(t) +// func (c *TestFoldProof[S, G1El, G2El, GTEl]) Define(api frontend.API) error { -// alpha, err := rand.Int(rand.Reader, ecc.BW6_761.ScalarField()) -// assert.NoError(err) -// srs, err := kzg_bw6761.NewSRS(kzgSize, alpha) -// assert.NoError(err) - -// f := make([]fr_bw6761.Element, polynomialSize) -// for i := range f { -// f[i].SetRandom() +// verifier, err := NewVerifier[S, G1El, G2El, GTEl](api) +// if err != nil { +// return fmt.Errorf("get pairing: %w", err) // } -// com, err := kzg_bw6761.Commit(f, srs.Pk) -// assert.NoError(err) - -// var point fr_bw6761.Element -// point.SetRandom() -// proof, err := kzg_bw6761.Open(f, point, srs.Pk) -// assert.NoError(err) - -// if err = kzg_bw6761.Verify(&com, &proof, point, srs.Vk); err != nil { -// t.Fatal("verify proof", err) -// } - -// wCmt, err := ValueOfCommitment[sw_bw6761.G1Affine](com) -// assert.NoError(err) -// wProof, err := ValueOfOpeningProof[sw_bw6761.Scalar, sw_bw6761.G1Affine](point, proof) -// assert.NoError(err) -// wVk, err := ValueOfVerifyingKey[sw_bw6761.G2Affine](srs.Vk) -// assert.NoError(err) - -// assignment := KZGVerificationCircuit[sw_bw6761.Scalar, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{ -// VerifyingKey: wVk, -// Commitment: wCmt, -// OpeningProof: wProof, -// } -// assert.CheckCircuit(&KZGVerificationCircuit[sw_bw6761.Scalar, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{}, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BN254)) -// } - -// func TestKZGVerificationTwoChain(t *testing.T) { -// assert := test.NewAssert(t) - -// alpha, err := rand.Int(rand.Reader, ecc.BLS12_377.ScalarField()) -// assert.NoError(err) -// srs, err := kzg_bls12377.NewSRS(kzgSize, alpha) -// assert.NoError(err) - -// f := make([]fr_bls12377.Element, polynomialSize) -// for i := range f { -// f[i].SetRandom() -// } - -// com, err := kzg_bls12377.Commit(f, srs.Pk) -// assert.NoError(err) - -// var point fr_bls12377.Element -// point.SetRandom() -// proof, err := kzg_bls12377.Open(f, point, srs.Pk) -// assert.NoError(err) - -// if err = kzg_bls12377.Verify(&com, &proof, point, srs.Vk); err != nil { -// t.Fatal("verify proof", err) -// } - -// wCmt, err := ValueOfCommitment[sw_bls12377.G1Affine](com) -// assert.NoError(err) -// wProof, err := ValueOfOpeningProof[sw_bls12377.Scalar, sw_bls12377.G1Affine](point, proof) -// assert.NoError(err) -// wVk, err := ValueOfVerifyingKey[sw_bls12377.G2Affine](srs.Vk) -// assert.NoError(err) - -// assignment := KZGVerificationCircuit[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ -// VerifyingKey: wVk, -// Commitment: wCmt, -// OpeningProof: wProof, -// } - -// assert.CheckCircuit(&KZGVerificationCircuit[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{}, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BW6_761)) -// } - -// func TestKZGVerificationTwoChain2(t *testing.T) { -// assert := test.NewAssert(t) - -// alpha, err := rand.Int(rand.Reader, ecc.BLS24_315.ScalarField()) -// assert.NoError(err) -// srs, err := kzg_bls24315.NewSRS(kzgSize, alpha) -// assert.NoError(err) - -// f := make([]fr_bls24315.Element, polynomialSize) -// for i := range f { -// f[i].SetRandom() -// } - -// com, err := kzg_bls24315.Commit(f, srs.Pk) -// assert.NoError(err) - -// var point fr_bls24315.Element -// point.SetRandom() -// proof, err := kzg_bls24315.Open(f, point, srs.Pk) -// assert.NoError(err) - -// if err = kzg_bls24315.Verify(&com, &proof, point, srs.Vk); err != nil { -// t.Fatal("verify proof", err) -// } - -// wCmt, err := ValueOfCommitment[sw_bls24315.G1Affine](com) -// assert.NoError(err) -// wProof, err := ValueOfOpeningProof[sw_bls24315.Scalar, sw_bls24315.G1Affine](point, proof) -// assert.NoError(err) -// wVk, err := ValueOfVerifyingKey[sw_bls24315.G2Affine](srs.Vk) -// assert.NoError(err) - -// assignment := KZGVerificationCircuit[sw_bls24315.Scalar, sw_bls24315.G1Affine, sw_bls24315.G2Affine, sw_bls24315.GT]{ -// VerifyingKey: wVk, -// Commitment: wCmt, -// OpeningProof: wProof, -// } - -// assert.CheckCircuit(&KZGVerificationCircuit[sw_bls24315.Scalar, sw_bls24315.G1Affine, sw_bls24315.G2Affine, sw_bls24315.GT]{}, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BW6_633)) -// } - -// func TestValueOfCommitment(t *testing.T) { -// assert := test.NewAssert(t) -// assert.Run(func(assert *test.Assert) { -// _, _, G1, _ := bn254.Generators() -// assignment, err := ValueOfCommitment[sw_bn254.G1Affine](G1) -// assert.NoError(err) -// _ = assignment -// }, "bn254") -// assert.Run(func(assert *test.Assert) { -// _, _, G1, _ := bls12377.Generators() -// assignment, err := ValueOfCommitment[sw_bls12377.G1Affine](G1) -// assert.NoError(err) -// _ = assignment -// }, "bls12377") -// assert.Run(func(assert *test.Assert) { -// _, _, G1, _ := bls12381.Generators() -// assignment, err := ValueOfCommitment[sw_bls12381.G1Affine](G1) -// assert.NoError(err) -// _ = assignment -// }, "bls12381") -// assert.Run(func(assert *test.Assert) { -// _, _, G1, _ := bw6761.Generators() -// assignment, err := ValueOfCommitment[sw_bw6761.G1Affine](G1) -// assert.NoError(err) -// _ = assignment -// }, "bw6761") -// assert.Run(func(assert *test.Assert) { -// _, _, G1, _ := bls24315.Generators() -// assignment, err := ValueOfCommitment[sw_bls24315.G1Affine](G1) -// assert.NoError(err) -// _ = assignment -// }, "bls24315") -// } - -// func TestValueOfOpeningProof(t *testing.T) { -// assert := test.NewAssert(t) -// assert.Run(func(assert *test.Assert) { -// _, _, G1, _ := bn254.Generators() -// var value, point fr_bn254.Element -// value.SetRandom() -// point.SetRandom() -// proof := kzg_bn254.OpeningProof{ -// H: G1, -// ClaimedValue: value, -// } -// assignment, err := ValueOfOpeningProof[sw_bn254.Scalar, sw_bn254.G1Affine](point, proof) -// assert.NoError(err) -// _ = assignment -// }, "bn254") -// assert.Run(func(assert *test.Assert) { -// _, _, G1, _ := bls12377.Generators() -// var value, point fr_bls12377.Element -// value.SetRandom() -// point.SetRandom() -// proof := kzg_bls12377.OpeningProof{ -// H: G1, -// ClaimedValue: value, -// } -// assignment, err := ValueOfOpeningProof[sw_bls12377.Scalar, sw_bls12377.G1Affine](point, proof) -// assert.NoError(err) -// _ = assignment -// }, "bls12377") -// assert.Run(func(assert *test.Assert) { -// _, _, G1, _ := bls12381.Generators() -// var value, point fr_bls12381.Element -// value.SetRandom() -// point.SetRandom() -// proof := kzg_bls12381.OpeningProof{ -// H: G1, -// ClaimedValue: value, -// } -// assignment, err := ValueOfOpeningProof[sw_bls12381.Scalar, sw_bls12381.G1Affine](point, proof) -// assert.NoError(err) -// _ = assignment -// }, "bls12381") -// assert.Run(func(assert *test.Assert) { -// _, _, G1, _ := bw6761.Generators() -// var value, point fr_bw6761.Element -// value.SetRandom() -// point.SetRandom() -// proof := kzg_bw6761.OpeningProof{ -// H: G1, -// ClaimedValue: value, -// } -// assignment, err := ValueOfOpeningProof[sw_bw6761.Scalar, sw_bw6761.G1Affine](point, proof) -// assert.NoError(err) -// _ = assignment -// }, "bw6761") -// assert.Run(func(assert *test.Assert) { -// _, _, G1, _ := bls24315.Generators() -// var value, point fr_bls24315.Element -// value.SetRandom() -// point.SetRandom() -// proof := kzg_bls24315.OpeningProof{ -// H: G1, -// ClaimedValue: value, -// } -// assignment, err := ValueOfOpeningProof[sw_bls24315.Scalar, sw_bls24315.G1Affine](point, proof) -// assert.NoError(err) -// _ = assignment -// }, "bls24315") -// } - -// func TestValueOfSRS(t *testing.T) { -// assert := test.NewAssert(t) -// assert.Run(func(assert *test.Assert) { -// _, _, _, G2 := bn254.Generators() -// vk := kzg_bn254.VerifyingKey{ -// G2: [2]bn254.G2Affine{G2, G2}, -// } -// assignment, err := ValueOfVerifyingKey[sw_bn254.G2Affine](vk) -// assert.NoError(err) -// _ = assignment -// }, "bn254") -// assert.Run(func(assert *test.Assert) { -// _, _, _, G2 := bls12377.Generators() -// vk := kzg_bls12377.VerifyingKey{ -// G2: [2]bls12377.G2Affine{G2, G2}, -// } -// assignment, err := ValueOfVerifyingKey[sw_bls12377.G2Affine](vk) -// assert.NoError(err) -// _ = assignment -// }, "bls12377") -// assert.Run(func(assert *test.Assert) { -// _, _, _, G2 := bls12381.Generators() -// vk := kzg_bls12381.VerifyingKey{ -// G2: [2]bls12381.G2Affine{G2, G2}, -// } -// assignment, err := ValueOfVerifyingKey[sw_bls12381.G2Affine](vk) -// assert.NoError(err) -// _ = assignment -// }, "bls12381") -// assert.Run(func(assert *test.Assert) { -// _, _, _, G2 := bw6761.Generators() -// vk := kzg_bw6761.VerifyingKey{ -// G2: [2]bw6761.G2Affine{G2, G2}, -// } -// assignment, err := ValueOfVerifyingKey[sw_bw6761.G2Affine](vk) -// assert.NoError(err) -// _ = assignment -// }, "bw6761") -// assert.Run(func(assert *test.Assert) { -// _, _, _, G2 := bls24315.Generators() -// vk := kzg_bls24315.VerifyingKey{ -// G2: [2]bls24315.G2Affine{G2, G2}, -// } -// assignment, err := ValueOfVerifyingKey[sw_bls24315.G2Affine](vk) -// assert.NoError(err) -// _ = assignment -// }, "bls24315") +// return nil // } diff --git a/std/fiat-shamir/transcript.go b/std/fiat-shamir/transcript.go index 8d507052e9..fcdae5a858 100644 --- a/std/fiat-shamir/transcript.go +++ b/std/fiat-shamir/transcript.go @@ -133,7 +133,14 @@ func (t *Transcript) ComputeChallenge(challengeID string, bitMod bool) (frontend if t.previous == nil || (t.previous.position != challenge.position-1) { return nil, errPreviousChallengeNotComputed } - t.h.Write(t.previous.value) + if bitMod { + nbBits := 8 * ((t.api.Compiler().Field().BitLen() + 7) / 8) + binPrevChallenge := t.api.ToBinary(t.previous.value, nbBits) + slices.Reverse(binPrevChallenge) + t.h.Write(binPrevChallenge[8:]...) + } else { + t.h.Write(t.previous.value) + } } // write the binded values in the order they were added diff --git a/std/fiat-shamir/transcript_test.go b/std/fiat-shamir/transcript_test.go index 381b08a23c..4ae6eeaa82 100644 --- a/std/fiat-shamir/transcript_test.go +++ b/std/fiat-shamir/transcript_test.go @@ -17,6 +17,7 @@ limitations under the License. package fiatshamir import ( + "fmt" "math/big" "testing" @@ -30,6 +31,7 @@ import ( "github.com/consensys/gnark/std/hash/mimc" "github.com/consensys/gnark/std/recursion" "github.com/consensys/gnark/test" + "golang.org/x/exp/slices" ) //------------------------------------------------------ @@ -150,8 +152,8 @@ func TestFiatShamir(t *testing.T) { // bitMode==true type FiatShamirCircuitBitMode struct { - // Bindings [3][4]frontend.Variable `gnark:",public"` - Challenges frontend.Variable + Bindings [2][4]frontend.Variable + Challenge [2]frontend.Variable } func (circuit *FiatShamirCircuitBitMode) Define(api frontend.API) error { @@ -170,14 +172,33 @@ func (circuit *FiatShamirCircuitBitMode) Define(api frontend.API) error { } // New transcript with 3 challenges to be derived - tsSnark := NewTranscript(api, whSnark, "alpha") + tsSnark := NewTranscript(api, whSnark, "alpha", "beta") + challengesNames := []string{"alpha", "beta"} - challenge, err := tsSnark.ComputeChallenge("alpha", true) - if err != nil { - return err + nbBitsFull := ((api.Compiler().Field().BitLen() + 7) / 8) * 8 + for j := 0; j < 2; j++ { + for i := 0; i < 4; i++ { + binBindings := api.ToBinary(circuit.Bindings[j][i], nbBitsFull) + slices.Reverse(binBindings) + err = tsSnark.Bind(challengesNames[j], binBindings) + if err != nil { + return err + } + } + } + + var challenges [2]frontend.Variable + for i := 0; i < 2; i++ { + challenges[i], err = tsSnark.ComputeChallenge(challengesNames[i], true) + if err != nil { + return err + } } - api.AssertIsEqual(challenge, circuit.Challenges) + api.Println(challenges[1]) + for i := 0; i < 2; i++ { + api.AssertIsEqual(challenges[i], circuit.Challenge[i]) + } return nil } @@ -206,15 +227,45 @@ func TestFiatShamirBitMode(t *testing.T) { wh, err := recursion.NewShort(curveID.ScalarField(), target) assert.NoError(err) - ts := fiatshamir.NewTranscript(wh, "alpha") + ts := fiatshamir.NewTranscript(wh, "alpha", "beta") - expectedChallenges, err := ts.ComputeChallenge("alpha") - assert.NoError(err) + var bindings [2][4]big.Int + for i := 0; i < 2; i++ { + for j := 0; j < 4; j++ { + bindings[i][j].SetUint64(uint64(i*i + j*j)) + } + } + + frSize := utils.ByteLen(curveID.ScalarField()) + buf := make([]byte, frSize) + challengesNames := []string{"alpha", "beta"} + for j := 0; j < 2; j++ { + for i := 0; i < 4; i++ { + err := ts.Bind(challengesNames[j], bindings[j][i].FillBytes(buf)) + assert.NoError(err) + } + } + + var expectedChallenges [2][]byte + for i := 0; i < 2; i++ { + expectedChallenges[i], err = ts.ComputeChallenge(challengesNames[i]) + assert.NoError(err) + } + var a big.Int + a.SetBytes(expectedChallenges[1]) + fmt.Println(a.String()) // instantiate the circuit with provided inputs var witness FiatShamirCircuitBitMode - witness.Challenges = expectedChallenges + for i := 0; i < 2; i++ { + witness.Challenge[i] = expectedChallenges[i] + } + for j := 0; j < 2; j++ { + for i := 0; i < 4; i++ { + witness.Bindings[j][i] = bindings[j][i] + } + } assert.CheckCircuit(&FiatShamirCircuitBitMode{}, test.WithValidAssignment(&witness), test.WithCurves(curveID)) } diff --git a/std/gkr/gkr.go b/std/gkr/gkr.go index 646ca45553..a0fd19c6f6 100644 --- a/std/gkr/gkr.go +++ b/std/gkr/gkr.go @@ -2,11 +2,12 @@ package gkr import ( "fmt" + "strconv" + "github.com/consensys/gnark/frontend" fiatshamir "github.com/consensys/gnark/std/fiat-shamir" "github.com/consensys/gnark/std/polynomial" "github.com/consensys/gnark/std/sumcheck" - "strconv" ) // @tabaie TODO: Contains many things copy-pasted from gnark-crypto. Generify somehow? @@ -291,7 +292,7 @@ func getFirstChallengeNames(logNbInstances int, prefix string) []string { func getChallenges(transcript *fiatshamir.Transcript, names []string) (challenges []frontend.Variable, err error) { challenges = make([]frontend.Variable, len(names)) for i, name := range names { - if challenges[i], err = transcript.ComputeChallenge(name); err != nil { + if challenges[i], err = transcript.ComputeChallenge(name, false); err != nil { return } } diff --git a/std/sumcheck/sumcheck.go b/std/sumcheck/sumcheck.go index e002dfc489..fbd7ff0288 100644 --- a/std/sumcheck/sumcheck.go +++ b/std/sumcheck/sumcheck.go @@ -2,10 +2,11 @@ package sumcheck import ( "fmt" + "strconv" + "github.com/consensys/gnark/frontend" fiatshamir "github.com/consensys/gnark/std/fiat-shamir" "github.com/consensys/gnark/std/polynomial" - "strconv" ) // LazyClaims is the Claims data structure on the verifier side. It is "lazy" in that it has to compute fewer things. @@ -50,7 +51,7 @@ func next(transcript *fiatshamir.Transcript, bindings []frontend.Variable, remai return nil, err } - res, err := transcript.ComputeChallenge(challengeName) + res, err := transcript.ComputeChallenge(challengeName, false) *remainingChallengeNames = (*remainingChallengeNames)[1:] return res, err } From d770d97ffcf517768c73b9b106fff557f90597d7 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Fri, 3 Nov 2023 10:21:32 +0100 Subject: [PATCH 07/15] feat: tests FS bitmod ok --- std/fiat-shamir/transcript_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/std/fiat-shamir/transcript_test.go b/std/fiat-shamir/transcript_test.go index 4ae6eeaa82..4e77dfb03c 100644 --- a/std/fiat-shamir/transcript_test.go +++ b/std/fiat-shamir/transcript_test.go @@ -208,13 +208,13 @@ func TestFiatShamirBitMode(t *testing.T) { assert := test.NewAssert(t) testData := map[ecc.ID]hash.Hash{ - ecc.BN254: hash.MIMC_BN254, - // ecc.BLS12_377: hash.MIMC_BLS12_377, - // ecc.BLS12_381: hash.MIMC_BLS12_381, - // ecc.BLS24_315: hash.MIMC_BLS24_315, - // ecc.BLS24_317: hash.MIMC_BLS24_317, - // ecc.BW6_761: hash.MIMC_BW6_761, - // ecc.BW6_633: hash.MIMC_BW6_633, + ecc.BN254: hash.MIMC_BN254, + ecc.BLS12_377: hash.MIMC_BLS12_377, + ecc.BLS12_381: hash.MIMC_BLS12_381, + ecc.BLS24_315: hash.MIMC_BLS24_315, + ecc.BLS24_317: hash.MIMC_BLS24_317, + ecc.BW6_761: hash.MIMC_BW6_761, + ecc.BW6_633: hash.MIMC_BW6_633, } // compute the witness for each curve From 4045b40b4c719f29a75af1e04e6cbfb9e773c08e Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Fri, 3 Nov 2023 15:57:06 +0100 Subject: [PATCH 08/15] feat: test folding wip --- std/commitments/kzg_refactor/conversion.go | 40 ++++++ std/commitments/kzg_refactor/verifier.go | 64 +++++----- std/commitments/kzg_refactor/verifier_test.go | 120 ++++++++++++++++-- 3 files changed, 180 insertions(+), 44 deletions(-) diff --git a/std/commitments/kzg_refactor/conversion.go b/std/commitments/kzg_refactor/conversion.go index 5d5f4f1ee3..815477bef1 100644 --- a/std/commitments/kzg_refactor/conversion.go +++ b/std/commitments/kzg_refactor/conversion.go @@ -99,6 +99,46 @@ func ValueOfCommitment[G1El any](cmt any) (Commitment[G1El], error) { return ret, nil } +func ValueOfBatchOpeningProof[S emulated.FieldParams, G1El any](proof any) (BatchOpeningProof[S, G1El], error) { + + var ret BatchOpeningProof[S, G1El] + switch s := any(&ret).(type) { + case *BatchOpeningProof[emulated.BN254Fr, sw_bn254.G1Affine]: + tProof, ok := proof.(kzg_bn254.BatchOpeningProof) + if !ok { + return ret, fmt.Errorf("mismatching types %T %T", ret, proof) + } + s.Quotient = sw_bn254.NewG1Affine(tProof.H) + s.ClaimedValues = make([]emulated.Element[emulated.BN254Fr], len(s.ClaimedValues)) + for i := 0; i < len(s.ClaimedValues); i++ { + s.ClaimedValues[i] = sw_bn254.NewScalar(tProof.ClaimedValues[i]) + } + case *BatchOpeningProof[emulated.BLS12381Fr, sw_bls12381.G1Affine]: + tProof, ok := proof.(kzg_bls12381.BatchOpeningProof) + if !ok { + return ret, fmt.Errorf("mismatching types %T %T", ret, proof) + } + s.Quotient = sw_bls12381.NewG1Affine(tProof.H) + s.ClaimedValues = make([]emulated.Element[emulated.BLS12381Fr], len(s.ClaimedValues)) + for i := 0; i < len(s.ClaimedValues); i++ { + s.ClaimedValues[i] = sw_bls12381.NewScalar(tProof.ClaimedValues[i]) + } + case *BatchOpeningProof[emulated.BW6761Fr, sw_bw6761.G1Affine]: + tProof, ok := proof.(kzg_bw6761.BatchOpeningProof) + if !ok { + return ret, fmt.Errorf("mismatching types %T %T", ret, proof) + } + s.Quotient = sw_bw6761.NewG1Affine(tProof.H) + s.ClaimedValues = make([]emulated.Element[emulated.BW6761Fr], len(s.ClaimedValues)) + for i := 0; i < len(s.ClaimedValues); i++ { + s.ClaimedValues[i] = sw_bw6761.NewScalar(tProof.ClaimedValues[i]) + } + default: + return ret, fmt.Errorf("unknown type parametrization") + } + return ret, nil +} + // ValueOfOpeningProof initializes an opening proof from the given proof and // point. It returns an error if there is a mismatch between the type parameters // and types of the provided point and proof. diff --git a/std/commitments/kzg_refactor/verifier.go b/std/commitments/kzg_refactor/verifier.go index a6b1327426..952b5e8ebc 100644 --- a/std/commitments/kzg_refactor/verifier.go +++ b/std/commitments/kzg_refactor/verifier.go @@ -6,6 +6,7 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra" + fiatshamir "github.com/consensys/gnark/std/fiat-shamir" "github.com/consensys/gnark/std/hash" "github.com/consensys/gnark/std/math/emulated" ) @@ -114,7 +115,7 @@ func (v *Verifier[S, G1El, G2El, GTEl]) FoldProof(digests []Commitment[G1El], ba } // derive the challenge γ, binded to the point and the commitments - gamma, err := deriveGamma(point, digests, batchOpeningProof.ClaimedValues, hf, dataTranscript...) + gamma, err := v.deriveGamma(point, digests, batchOpeningProof.ClaimedValues, hf, dataTranscript...) if err != nil { return OpeningProof[S, G1El]{}, Commitment[G1El]{}, err } @@ -266,36 +267,37 @@ func (v *Verifier[S, G1El, G2El, GTEl]) BatchVerifyMultiPoints(digests []Commitm } // deriveGamma derives a challenge using Fiat Shamir to fold proofs. -func deriveGamma[S emulated.FieldParams, G1El any](point emulated.Element[S], digests []Commitment[G1El], claimedValues []emulated.Element[S], hf hash.FieldHasher, dataTranscript ...frontend.Variable) (emulated.Element[S], error) { +// dataTranscript are supposed to be bits. +func (v *Verifier[S, G1El, G2El, GTEl]) deriveGamma(point emulated.Element[S], digests []Commitment[G1El], claimedValues []emulated.Element[S], hf hash.FieldHasher, dataTranscript ...frontend.Variable) (emulated.Element[S], error) { // derive the challenge gamma, binded to the point and the commitments - // fs := fiatshamir.NewTranscript(hf, "gamma") - // if err := fs.Bind("gamma", point.Marshal()); err != nil { - // return fr.Element{}, err - // } - // for i := range digests { - // if err := fs.Bind("gamma", digests[i].Marshal()); err != nil { - // return fr.Element{}, err - // } - // } - // for i := range claimedValues { - // if err := fs.Bind("gamma", claimedValues[i].Marshal()); err != nil { - // return fr.Element{}, err - // } - // } - - // for i := 0; i < len(dataTranscript); i++ { - // if err := fs.Bind("gamma", dataTranscript[i]); err != nil { - // return fr.Element{}, err - // } - // } - - // gammaByte, err := fs.ComputeChallenge("gamma") - // if err != nil { - // return fr.Element{}, err - // } - // var gamma fr.Element - // gamma.SetBytes(gammaByte) - - return point, nil + fs := fiatshamir.NewTranscript(v.api, hf, "gamma") + + marhsalledPoint := v.ec.MarshalScalar(point) + if err := fs.Bind("gamma", marhsalledPoint); err != nil { + return emulated.Element[S]{}, err + } + for i := range digests { + if err := fs.Bind("gamma", v.ec.MarshalG1(digests[i].G1El)); err != nil { + return emulated.Element[S]{}, err + } + } + for i := range claimedValues { + if err := fs.Bind("gamma", v.ec.MarshalScalar(claimedValues[i])); err != nil { + return emulated.Element[S]{}, err + } + } + + if err := fs.Bind("gamma", dataTranscript); err != nil { + return emulated.Element[S]{}, err + } + + gamma, err := fs.ComputeChallenge("gamma", true) + if err != nil { + return emulated.Element[S]{}, err + } + bGamma := v.api.ToBinary(gamma) + gammaS := v.scalarApi.FromBits(bGamma) + + return *gammaS, nil } diff --git a/std/commitments/kzg_refactor/verifier_test.go b/std/commitments/kzg_refactor/verifier_test.go index ccd42b81bd..afe00159ec 100644 --- a/std/commitments/kzg_refactor/verifier_test.go +++ b/std/commitments/kzg_refactor/verifier_test.go @@ -3,6 +3,7 @@ package kzg_refactor import ( "crypto/rand" "fmt" + "math/big" "testing" "github.com/consensys/gnark-crypto/ecc" @@ -12,6 +13,7 @@ import ( "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra/emulated/sw_bn254" "github.com/consensys/gnark/std/math/emulated" + "github.com/consensys/gnark/std/recursion" "github.com/consensys/gnark/test" ) @@ -42,6 +44,7 @@ func (c *KZGVerificationCircuit[S, G1El, G2El, GTEl]) Define(api frontend.API) e } func TestKZGVerificationEmulated(t *testing.T) { + assert := test.NewAssert(t) alpha, err := rand.Int(rand.Reader, ecc.BN254.ScalarField()) @@ -89,19 +92,110 @@ func TestKZGVerificationEmulated(t *testing.T) { //-------------------------------------------------------- // Fold proof -// type TestFoldProof[S emulated.FieldParams, G1El, G2El, GTEl any] struct { -// Vk VerifyingKey[G1El, G2El] -// Point emulated.Element[S] -// Digests [10]Commitment[G1El] -// BatchOpeningProof OpeningProof[S, G1El] -// } +type FoldProofTest[S emulated.FieldParams, G1El, G2El, GTEl any] struct { + Vk VerifyingKey[G1El, G2El] + Point emulated.Element[S] + Digests [10]Commitment[G1El] + BatchOpeningProof BatchOpeningProof[S, G1El] + ExpectedFoldedProof OpeningProof[S, G1El] + ExpectedFoldedDigest Commitment[G1El] +} + +func (c *FoldProofTest[S, G1El, G2El, GTEl]) Define(api frontend.API) error { -// func (c *TestFoldProof[S, G1El, G2El, GTEl]) Define(api frontend.API) error { + verifier, err := NewVerifier[S, G1El, G2El, GTEl](api) + if err != nil { + return fmt.Errorf("get pairing: %w", err) + } -// verifier, err := NewVerifier[S, G1El, G2El, GTEl](api) -// if err != nil { -// return fmt.Errorf("get pairing: %w", err) -// } + // pick a number on byte shorter than the modulus size + var target big.Int + target.SetUint64(1) + nbBits := api.Compiler().Field().BitLen() + nn := ((nbBits+7)/8)*8 - 8 + target.Lsh(&target, uint(nn)) + + // create the wrapped hash function + whSnark, err := recursion.NewHash(api, &target, true) + if err != nil { + return err + } + + op, com, err := verifier.FoldProof(c.Digests[:], c.BatchOpeningProof, c.Point, whSnark) + if err != nil { + return err + } + + verifier.ec.AssertIsEqual(&com.G1El, &c.ExpectedFoldedDigest.G1El) + verifier.ec.AssertIsEqual(&c.ExpectedFoldedProof.Quotient, &op.Quotient) + verifier.scalarApi.AssertIsEqual(&op.ClaimedValue, &c.ExpectedFoldedProof.ClaimedValue) + + return nil +} + +func TestFoldProof(t *testing.T) { + + assert := test.NewAssert(t) + + // prepare test data + alpha, err := rand.Int(rand.Reader, ecc.BN254.ScalarField()) + assert.NoError(err) + srs, err := kzg_bn254.NewSRS(kzgSize, alpha) + assert.NoError(err) -// return nil -// } + var polynomials [10][]fr_bn254.Element + var coms [10]kzg_bn254.Digest + for i := 0; i < 10; i++ { + polynomials[i] = make([]fr_bn254.Element, polynomialSize) + for j := 0; j < polynomialSize; j++ { + polynomials[i][j].SetRandom() + } + coms[i], err = kzg_bn254.Commit(polynomials[i], srs.Pk) + assert.NoError(err) + } + + var point fr_bn254.Element + point.SetRandom() + var target big.Int + target.SetUint64(1) + nbBits := ecc.BN254.ScalarField().BitLen() + nn := ((nbBits+7)/8)*8 - 8 + target.Lsh(&target, uint(nn)) + h, err := recursion.NewShort(ecc.BN254.ScalarField(), &target) + assert.NoError(err) + + batchOpeningProof, err := kzg_bn254.BatchOpenSinglePoint(polynomials[:], coms[:], point, h, srs.Pk) + assert.NoError(err) + + foldedProofs, foldedDigest, err := kzg_bn254.FoldProof(coms[:], &batchOpeningProof, point, h) + assert.NoError(err) + + // prepare witness + wVk, err := ValueOfVerifyingKey[sw_bn254.G1Affine, sw_bn254.G2Affine](srs.Vk) + assert.NoError(err) + wPoint, err := ValueOfScalar[emulated.BN254Fr](point) + assert.NoError(err) + var wDigests [10]Commitment[sw_bn254.G1Affine] + for i := 0; i < 10; i++ { + wDigests[i], err = ValueOfCommitment[sw_bn254.G1Affine](coms[i]) + assert.NoError(err) + } + wBatchOpeningProof, err := ValueOfBatchOpeningProof[emulated.BN254Fr, sw_bn254.G1Affine](batchOpeningProof) + assert.NoError(err) + wExpectedFoldedProof, err := ValueOfOpeningProof[emulated.BN254Fr, sw_bn254.G1Affine](foldedProofs) + assert.NoError(err) + wExpectedFoldedDigest, err := ValueOfCommitment[sw_bn254.G1Affine](foldedDigest) + assert.NoError(err) + + assignment := FoldProofTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ + Vk: wVk, + Point: wPoint, + Digests: wDigests, + BatchOpeningProof: wBatchOpeningProof, + ExpectedFoldedProof: wExpectedFoldedProof, + ExpectedFoldedDigest: wExpectedFoldedDigest, + } + + assert.CheckCircuit(&KZGVerificationCircuit[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{}, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) + +} From 448a9f3e05d1124a15546544923cdecd4081b1b7 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Fri, 3 Nov 2023 18:43:08 +0100 Subject: [PATCH 09/15] fix: fixed ValueOfBatchOpeningProof --- std/commitments/kzg_refactor/conversion.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/std/commitments/kzg_refactor/conversion.go b/std/commitments/kzg_refactor/conversion.go index 815477bef1..1bbae7ea0d 100644 --- a/std/commitments/kzg_refactor/conversion.go +++ b/std/commitments/kzg_refactor/conversion.go @@ -109,7 +109,7 @@ func ValueOfBatchOpeningProof[S emulated.FieldParams, G1El any](proof any) (Batc return ret, fmt.Errorf("mismatching types %T %T", ret, proof) } s.Quotient = sw_bn254.NewG1Affine(tProof.H) - s.ClaimedValues = make([]emulated.Element[emulated.BN254Fr], len(s.ClaimedValues)) + s.ClaimedValues = make([]emulated.Element[emulated.BN254Fr], len(tProof.ClaimedValues)) for i := 0; i < len(s.ClaimedValues); i++ { s.ClaimedValues[i] = sw_bn254.NewScalar(tProof.ClaimedValues[i]) } @@ -119,7 +119,7 @@ func ValueOfBatchOpeningProof[S emulated.FieldParams, G1El any](proof any) (Batc return ret, fmt.Errorf("mismatching types %T %T", ret, proof) } s.Quotient = sw_bls12381.NewG1Affine(tProof.H) - s.ClaimedValues = make([]emulated.Element[emulated.BLS12381Fr], len(s.ClaimedValues)) + s.ClaimedValues = make([]emulated.Element[emulated.BLS12381Fr], len(tProof.ClaimedValues)) for i := 0; i < len(s.ClaimedValues); i++ { s.ClaimedValues[i] = sw_bls12381.NewScalar(tProof.ClaimedValues[i]) } @@ -129,7 +129,7 @@ func ValueOfBatchOpeningProof[S emulated.FieldParams, G1El any](proof any) (Batc return ret, fmt.Errorf("mismatching types %T %T", ret, proof) } s.Quotient = sw_bw6761.NewG1Affine(tProof.H) - s.ClaimedValues = make([]emulated.Element[emulated.BW6761Fr], len(s.ClaimedValues)) + s.ClaimedValues = make([]emulated.Element[emulated.BW6761Fr], len(tProof.ClaimedValues)) for i := 0; i < len(s.ClaimedValues); i++ { s.ClaimedValues[i] = sw_bw6761.NewScalar(tProof.ClaimedValues[i]) } From 9c07e8371b606259b1ca074fff106852b10b8c66 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Fri, 3 Nov 2023 19:59:11 +0100 Subject: [PATCH 10/15] feat: FoldProof test ok --- std/commitments/kzg_refactor/verifier.go | 18 +- std/commitments/kzg_refactor/verifier_test.go | 181 +++++++++++++++++- 2 files changed, 185 insertions(+), 14 deletions(-) diff --git a/std/commitments/kzg_refactor/verifier.go b/std/commitments/kzg_refactor/verifier.go index 952b5e8ebc..b266115dc2 100644 --- a/std/commitments/kzg_refactor/verifier.go +++ b/std/commitments/kzg_refactor/verifier.go @@ -128,17 +128,21 @@ func (v *Verifier[S, G1El, G2El, GTEl]) FoldProof(digests []Commitment[G1El], ba gammai[1] = gamma } for i := 2; i < nbDigests; i++ { - v.scalarApi.Mul(&gammai[i-1], &gamma) + gammai[i] = *(v.scalarApi.Mul(&gammai[i-1], &gamma)) } foldedDigests, foldedEvaluations := v.fold(digests, batchOpeningProof.ClaimedValues, gammai) - // create the folded opening proof - var res OpeningProof[S, G1El] - res.ClaimedValue = foldedEvaluations - res.Quotient = batchOpeningProof.Quotient + var foldedProof OpeningProof[S, G1El] + foldedProof.Quotient = batchOpeningProof.Quotient + foldedProof.ClaimedValue = foldedEvaluations + return foldedProof, foldedDigests, nil - return res, foldedDigests, nil + // create the folded opening proof + // var res OpeningProof[S, G1El] + // res.ClaimedValue = batchOpeningProof.ClaimedValues[0] + // res.Quotient = batchOpeningProof.Quotient + // return res, digests[0], nil } @@ -297,7 +301,7 @@ func (v *Verifier[S, G1El, G2El, GTEl]) deriveGamma(point emulated.Element[S], d return emulated.Element[S]{}, err } bGamma := v.api.ToBinary(gamma) - gammaS := v.scalarApi.FromBits(bGamma) + gammaS := v.scalarApi.FromBits(bGamma...) return *gammaS, nil } diff --git a/std/commitments/kzg_refactor/verifier_test.go b/std/commitments/kzg_refactor/verifier_test.go index afe00159ec..ada115caf6 100644 --- a/std/commitments/kzg_refactor/verifier_test.go +++ b/std/commitments/kzg_refactor/verifier_test.go @@ -89,6 +89,69 @@ func TestKZGVerificationEmulated(t *testing.T) { assert.CheckCircuit(&KZGVerificationCircuit[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{}, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) } +//-------------------------------------------------------- +// Slice proof + +// type SliceTest[S emulated.FieldParams, G1El any] struct { +// Proof BatchOpeningProof[S, G1El] +// } + +// func (circuit *SliceTest[S, G1El]) Define(api frontend.API) error { + +// fmt.Println(len(circuit.Proof.ClaimedValues)) +// return nil +// } + +// func TestSlices(t *testing.T) { + +// assert := test.NewAssert(t) + +// // prepare test data +// alpha, err := rand.Int(rand.Reader, ecc.BN254.ScalarField()) +// assert.NoError(err) +// srs, err := kzg_bn254.NewSRS(kzgSize, alpha) +// assert.NoError(err) + +// var polynomials [10][]fr_bn254.Element +// var coms [10]kzg_bn254.Digest +// for i := 0; i < 10; i++ { +// polynomials[i] = make([]fr_bn254.Element, polynomialSize) +// for j := 0; j < polynomialSize; j++ { +// polynomials[i][j].SetRandom() +// } +// coms[i], err = kzg_bn254.Commit(polynomials[i], srs.Pk) +// assert.NoError(err) +// } + +// var point fr_bn254.Element +// point.SetRandom() +// var target big.Int +// target.SetUint64(1) +// nbBits := ecc.BLS12_381.ScalarField().BitLen() +// nn := ((nbBits+7)/8)*8 - 8 +// target.Lsh(&target, uint(nn)) +// h, err := recursion.NewShort(ecc.BLS12_381.ScalarField(), &target) +// assert.NoError(err) + +// batchOpeningProof, err := kzg_bn254.BatchOpenSinglePoint(polynomials[:], coms[:], point, h, srs.Pk) +// assert.NoError(err) + +// _, _, err = kzg_bn254.FoldProof(coms[:], &batchOpeningProof, point, h) +// assert.NoError(err) + +// // circuit +// var circuit SliceTest[emulated.BN254Fr, sw_bn254.G1Affine] +// circuit.Proof.ClaimedValues = make([]emulated.Element[emulated.BN254Fr], 10) + +// var assignment SliceTest[emulated.BN254Fr, sw_bn254.G1Affine] +// // assignment.Proof.ClaimedValues = make([]emulated.Element[emulated.BN254Fr], 10) +// assignment.Proof, err = ValueOfBatchOpeningProof[emulated.BN254Fr, sw_bn254.G1Affine](batchOpeningProof) +// assert.NoError(err) + +// assert.CheckCircuit(&circuit, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) + +// } + //-------------------------------------------------------- // Fold proof @@ -121,14 +184,15 @@ func (c *FoldProofTest[S, G1El, G2El, GTEl]) Define(api frontend.API) error { return err } - op, com, err := verifier.FoldProof(c.Digests[:], c.BatchOpeningProof, c.Point, whSnark) + // op, com, err := verifier.FoldProof(c.Digests[:], c.BatchOpeningProof, c.Point, whSnark) + foldedProof, foldedDigests, err := verifier.FoldProof(c.Digests[:], c.BatchOpeningProof, c.Point, whSnark) if err != nil { return err } - verifier.ec.AssertIsEqual(&com.G1El, &c.ExpectedFoldedDigest.G1El) - verifier.ec.AssertIsEqual(&c.ExpectedFoldedProof.Quotient, &op.Quotient) - verifier.scalarApi.AssertIsEqual(&op.ClaimedValue, &c.ExpectedFoldedProof.ClaimedValue) + verifier.ec.AssertIsEqual(&foldedDigests.G1El, &c.ExpectedFoldedDigest.G1El) + verifier.ec.AssertIsEqual(&foldedProof.Quotient, &c.ExpectedFoldedProof.Quotient) + verifier.scalarApi.AssertIsEqual(&foldedProof.ClaimedValue, &c.ExpectedFoldedProof.ClaimedValue) return nil } @@ -158,10 +222,10 @@ func TestFoldProof(t *testing.T) { point.SetRandom() var target big.Int target.SetUint64(1) - nbBits := ecc.BN254.ScalarField().BitLen() + nbBits := ecc.BLS12_381.ScalarField().BitLen() nn := ((nbBits+7)/8)*8 - 8 target.Lsh(&target, uint(nn)) - h, err := recursion.NewShort(ecc.BN254.ScalarField(), &target) + h, err := recursion.NewShort(ecc.BLS12_381.ScalarField(), &target) assert.NoError(err) batchOpeningProof, err := kzg_bn254.BatchOpenSinglePoint(polynomials[:], coms[:], point, h, srs.Pk) @@ -196,6 +260,109 @@ func TestFoldProof(t *testing.T) { ExpectedFoldedDigest: wExpectedFoldedDigest, } - assert.CheckCircuit(&KZGVerificationCircuit[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{}, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) + var circuit FoldProofTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl] + circuit.BatchOpeningProof.ClaimedValues = make([]emulated.Element[emulated.BN254Fr], 10) + assert.CheckCircuit(&circuit, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) + +} + +//-------------------------------------------------------- +// derive gamma + +type DeriveGammaTest[S emulated.FieldParams, G1El, G2El, GTEl any] struct { + Point emulated.Element[S] + Digests [10]Commitment[G1El] + ClaimedValues [10]emulated.Element[S] + Gamma emulated.Element[S] +} + +func (circuit *DeriveGammaTest[S, G1El, G2El, GTEl]) Define(api frontend.API) error { + + verifier, err := NewVerifier[S, G1El, G2El, GTEl](api) + if err != nil { + return fmt.Errorf("get pairing: %w", err) + } + + // pick a number on byte shorter than the modulus size + var target big.Int + target.SetUint64(1) + nbBits := api.Compiler().Field().BitLen() + nn := ((nbBits+7)/8)*8 - 8 + target.Lsh(&target, uint(nn)) + + // create the wrapped hash function + whSnark, err := recursion.NewHash(api, &target, true) + if err != nil { + return err + } + + res, err := verifier.deriveGamma(circuit.Point, circuit.Digests[:], circuit.ClaimedValues[:], whSnark) + if err != nil { + return err + } + verifier.scalarApi.AssertIsEqual(&res, &circuit.Gamma) + return nil +} + +func TestDeriveGamma(t *testing.T) { + + assert := test.NewAssert(t) + + // prepare test data + alpha, err := rand.Int(rand.Reader, ecc.BN254.ScalarField()) + assert.NoError(err) + srs, err := kzg_bn254.NewSRS(kzgSize, alpha) + assert.NoError(err) + + var polynomials [10][]fr_bn254.Element + var digests [10]kzg_bn254.Digest + for i := 0; i < 10; i++ { + polynomials[i] = make([]fr_bn254.Element, polynomialSize) + for j := 0; j < polynomialSize; j++ { + polynomials[i][j].SetRandom() + } + digests[i], err = kzg_bn254.Commit(polynomials[i], srs.Pk) + assert.NoError(err) + } + + var point fr_bn254.Element + point.SetRandom() + var target big.Int + target.SetUint64(1) + nbBits := ecc.BLS12_381.ScalarField().BitLen() + nn := ((nbBits+7)/8)*8 - 8 + target.Lsh(&target, uint(nn)) + h, err := recursion.NewShort(ecc.BLS12_381.ScalarField(), &target) + assert.NoError(err) + + batchOpeningProof, err := kzg_bn254.BatchOpenSinglePoint(polynomials[:], digests[:], point, h, srs.Pk) + assert.NoError(err) + + gamma, err := kzg_bn254.DeriveGamma(point, digests[:], batchOpeningProof.ClaimedValues, h) + assert.NoError(err) + + // prepare witness + wPoint, err := ValueOfScalar[emulated.BN254Fr](point) + assert.NoError(err) + var wDigests [10]Commitment[sw_bn254.G1Affine] + for i := 0; i < 10; i++ { + wDigests[i], err = ValueOfCommitment[sw_bn254.G1Affine](digests[i]) + assert.NoError(err) + } + var wClaimedValues [10]emulated.Element[emulated.BN254Fr] + for i := 0; i < 10; i++ { + wClaimedValues[i], err = ValueOfScalar[emulated.BN254Fr](batchOpeningProof.ClaimedValues[i]) + assert.NoError(err) + } + wGmma, err := ValueOfScalar[emulated.BN254Fr](gamma) + assert.NoError(err) + + assignment := DeriveGammaTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ + Point: wPoint, + Digests: wDigests, + ClaimedValues: wClaimedValues, + Gamma: wGmma, + } + assert.CheckCircuit(&DeriveGammaTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{}, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) } From 00819710279245878f53cb8aa4da276a7d7bb5f7 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Fri, 3 Nov 2023 22:55:08 +0100 Subject: [PATCH 11/15] feat: batchVerifySinglePoint ok --- std/commitments/kzg_refactor/verifier.go | 1 + std/commitments/kzg_refactor/verifier_test.go | 103 +++++++++++++++++- 2 files changed, 100 insertions(+), 4 deletions(-) diff --git a/std/commitments/kzg_refactor/verifier.go b/std/commitments/kzg_refactor/verifier.go index b266115dc2..431454412e 100644 --- a/std/commitments/kzg_refactor/verifier.go +++ b/std/commitments/kzg_refactor/verifier.go @@ -272,6 +272,7 @@ func (v *Verifier[S, G1El, G2El, GTEl]) BatchVerifyMultiPoints(digests []Commitm // deriveGamma derives a challenge using Fiat Shamir to fold proofs. // dataTranscript are supposed to be bits. +// /!\ bitMode = true here /!\ func (v *Verifier[S, G1El, G2El, GTEl]) deriveGamma(point emulated.Element[S], digests []Commitment[G1El], claimedValues []emulated.Element[S], hf hash.FieldHasher, dataTranscript ...frontend.Variable) (emulated.Element[S], error) { // derive the challenge gamma, binded to the point and the commitments diff --git a/std/commitments/kzg_refactor/verifier_test.go b/std/commitments/kzg_refactor/verifier_test.go index ada115caf6..c0f251f3f2 100644 --- a/std/commitments/kzg_refactor/verifier_test.go +++ b/std/commitments/kzg_refactor/verifier_test.go @@ -156,7 +156,6 @@ func TestKZGVerificationEmulated(t *testing.T) { // Fold proof type FoldProofTest[S emulated.FieldParams, G1El, G2El, GTEl any] struct { - Vk VerifyingKey[G1El, G2El] Point emulated.Element[S] Digests [10]Commitment[G1El] BatchOpeningProof BatchOpeningProof[S, G1El] @@ -235,8 +234,6 @@ func TestFoldProof(t *testing.T) { assert.NoError(err) // prepare witness - wVk, err := ValueOfVerifyingKey[sw_bn254.G1Affine, sw_bn254.G2Affine](srs.Vk) - assert.NoError(err) wPoint, err := ValueOfScalar[emulated.BN254Fr](point) assert.NoError(err) var wDigests [10]Commitment[sw_bn254.G1Affine] @@ -252,7 +249,6 @@ func TestFoldProof(t *testing.T) { assert.NoError(err) assignment := FoldProofTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ - Vk: wVk, Point: wPoint, Digests: wDigests, BatchOpeningProof: wBatchOpeningProof, @@ -266,6 +262,105 @@ func TestFoldProof(t *testing.T) { } +//-------------------------------------------------------- +// Batch verify single point + +type BatchVerifySinglePointTest[S emulated.FieldParams, G1El, G2El, GTEl any] struct { + Vk VerifyingKey[G1El, G2El] + Point emulated.Element[S] + Digests [10]Commitment[G1El] + BatchOpeningProof BatchOpeningProof[S, G1El] +} + +func (c *BatchVerifySinglePointTest[S, G1El, G2El, GTEl]) Define(api frontend.API) error { + + verifier, err := NewVerifier[S, G1El, G2El, GTEl](api) + if err != nil { + return fmt.Errorf("get pairing: %w", err) + } + + // pick a number on byte shorter than the modulus size + var target big.Int + target.SetUint64(1) + nbBits := api.Compiler().Field().BitLen() + nn := ((nbBits+7)/8)*8 - 8 + target.Lsh(&target, uint(nn)) + + // create the wrapped hash function + whSnark, err := recursion.NewHash(api, &target, true) + if err != nil { + return err + } + + // op, com, err := verifier.FoldProof(c.Digests[:], c.BatchOpeningProof, c.Point, whSnark) + verifier.BatchVerifySinglePoint(c.Digests[:], c.BatchOpeningProof, c.Point, whSnark, c.Vk) + + return nil +} + +func TestBatchVerifySinglePoint(t *testing.T) { + + assert := test.NewAssert(t) + + // prepare test data + alpha, err := rand.Int(rand.Reader, ecc.BN254.ScalarField()) + assert.NoError(err) + srs, err := kzg_bn254.NewSRS(kzgSize, alpha) + assert.NoError(err) + + var polynomials [10][]fr_bn254.Element + var coms [10]kzg_bn254.Digest + for i := 0; i < 10; i++ { + polynomials[i] = make([]fr_bn254.Element, polynomialSize) + for j := 0; j < polynomialSize; j++ { + polynomials[i][j].SetRandom() + } + coms[i], err = kzg_bn254.Commit(polynomials[i], srs.Pk) + assert.NoError(err) + } + + var point fr_bn254.Element + point.SetRandom() + var target big.Int + target.SetUint64(1) + nbBits := ecc.BLS12_381.ScalarField().BitLen() + nn := ((nbBits+7)/8)*8 - 8 + target.Lsh(&target, uint(nn)) + h, err := recursion.NewShort(ecc.BLS12_381.ScalarField(), &target) + assert.NoError(err) + + batchOpeningProof, err := kzg_bn254.BatchOpenSinglePoint(polynomials[:], coms[:], point, h, srs.Pk) + assert.NoError(err) + + err = kzg_bn254.BatchVerifySinglePoint(coms[:], &batchOpeningProof, point, h, srs.Vk) + assert.NoError(err) + + // prepare witness + wVk, err := ValueOfVerifyingKey[sw_bn254.G1Affine, sw_bn254.G2Affine](srs.Vk) + assert.NoError(err) + wPoint, err := ValueOfScalar[emulated.BN254Fr](point) + assert.NoError(err) + var wDigests [10]Commitment[sw_bn254.G1Affine] + for i := 0; i < 10; i++ { + wDigests[i], err = ValueOfCommitment[sw_bn254.G1Affine](coms[i]) + assert.NoError(err) + } + wBatchOpeningProof, err := ValueOfBatchOpeningProof[emulated.BN254Fr, sw_bn254.G1Affine](batchOpeningProof) + assert.NoError(err) + + assignment := BatchVerifySinglePointTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ + Vk: wVk, + Point: wPoint, + Digests: wDigests, + BatchOpeningProof: wBatchOpeningProof, + } + + var circuit BatchVerifySinglePointTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl] + circuit.BatchOpeningProof.ClaimedValues = make([]emulated.Element[emulated.BN254Fr], 10) + assert.CheckCircuit(&circuit, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) + +} + //-------------------------------------------------------- // derive gamma From d0136b590d2a5673e233d51cd9037a27980eea63 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Tue, 7 Nov 2023 12:43:11 +0100 Subject: [PATCH 12/15] fix: batch verify multi point ok --- std/commitments/kzg_refactor/verifier.go | 91 +++++--- std/commitments/kzg_refactor/verifier_test.go | 211 +++++++++++++----- 2 files changed, 214 insertions(+), 88 deletions(-) diff --git a/std/commitments/kzg_refactor/verifier.go b/std/commitments/kzg_refactor/verifier.go index 431454412e..1d6200e02f 100644 --- a/std/commitments/kzg_refactor/verifier.go +++ b/std/commitments/kzg_refactor/verifier.go @@ -146,32 +146,6 @@ func (v *Verifier[S, G1El, G2El, GTEl]) FoldProof(digests []Commitment[G1El], ba } -func (v *Verifier[S, G1El, G2El, GTEl]) fold(digests []Commitment[G1El], fai, ci []emulated.Element[S]) (Commitment[G1El], emulated.Element[S]) { - - // length inconsistency between digests and evaluations should have been done before calling this function - nbDigests := len(digests) - - // fold the claimed values ∑ᵢcᵢf(aᵢ) - var foldedEvaluations, tmp emulated.Element[S] - foldedEvaluations = emulated.ValueOf[S](0) - for i := 0; i < nbDigests; i++ { - tmp = *v.scalarApi.Mul(&fai[i], &ci[i]) - foldedEvaluations = *v.scalarApi.Add(&foldedEvaluations, &tmp) - } - - // fold the digests ∑ᵢ[cᵢ]([fᵢ(α)]G₁) - var foldedDigests Commitment[G1El] - foldedDigests.G1El = *v.ec.ScalarMul(&digests[0].G1El, &ci[0]) - for i := 1; i < nbDigests; i++ { - tmp := *v.ec.ScalarMul(&digests[i].G1El, &ci[i]) - foldedDigests.G1El = *v.ec.Add(&tmp, &foldedDigests.G1El) - } - - // folding done - return foldedDigests, foldedEvaluations - -} - func (v *Verifier[S, G1El, G2El, GTEl]) BatchVerifySinglePoint(digests []Commitment[G1El], batchOpeningProof BatchOpeningProof[S, G1El], point emulated.Element[S], hf hash.FieldHasher, vk VerifyingKey[G1El, G2El], dataTranscript ...frontend.Variable) error { // fold the proof @@ -222,20 +196,48 @@ func (v *Verifier[S, G1El, G2El, GTEl]) BatchVerifyMultiPoints(digests []Commitm tmp := *v.ec.ScalarMul("ients[i], &randomNumbers[i]) foldedQuotients = *v.ec.Add(&tmp, &foldedQuotients) } + // aa := v.ec.MarshalG1(foldedQuotients) + // slices.Reverse(aa[:256]) + // slices.Reverse(aa[256:]) + // xx := v.api.FromBinary(aa[:256]...) + // yy := v.api.FromBinary(aa[256:]...) + // v.api.Println(xx) + // v.api.Println(yy) // fold digests and evals evals := make([]emulated.Element[S], len(digests)) - for i := 0; i < len(randomNumbers); i++ { - evals[i] = proofs[i].ClaimedValue - } // fold the digests: ∑ᵢλᵢ[f_i(α)]G₁ // fold the evals : ∑ᵢλᵢfᵢ(aᵢ) + for i := 0; i < len(digests); i++ { + + evals[i] = proofs[i].ClaimedValue + + // aa := v.scalarApi.ToBits(&proofs[i].ClaimedValue) + // bb := v.api.FromBinary(aa...) + // v.api.Println(bb) + } foldedDigests, foldedEvals := v.fold(digests, evals, randomNumbers) + // bb := v.scalarApi.ToBits(&foldedEvals) + // bbb := v.api.FromBinary(bb...) + // v.api.Println(bbb) + + // aa := v.ec.MarshalG1(foldedDigests.G1El) + // slices.Reverse(aa[:256]) + // slices.Reverse(aa[256:]) + // xx := v.api.FromBinary(aa[:256]...) + // yy := v.api.FromBinary(aa[256:]...) + // v.api.Println(xx) + // v.api.Println(yy) + // compute commitment to folded Eval [∑ᵢλᵢfᵢ(aᵢ)]G₁ foldedEvalsCommit := v.ec.ScalarMul(&vk.G1, &foldedEvals) + // bb := v.scalarApi.ToBits(&foldedEvals) + // bbb := v.api.FromBinary(bb...) + // v.api.Println(bbb) + // compute foldedDigests = ∑ᵢλᵢ[fᵢ(α)]G₁ - [∑ᵢλᵢfᵢ(aᵢ)]G₁ // foldedDigests.Sub(&foldedDigests, &foldedEvalsCommit) tmp := v.ec.Neg(foldedEvalsCommit) @@ -246,10 +248,11 @@ func (v *Verifier[S, G1El, G2El, GTEl]) BatchVerifyMultiPoints(digests []Commitm var foldedPointsQuotients G1El for i := 0; i < len(randomNumbers); i++ { randomNumbers[i] = *v.scalarApi.Mul(&randomNumbers[i], &points[i]) + // randomNumbers[i] = *v.scalarApi.Reduce(&randomNumbers[i]) } - foldedPointsQuotients = *v.ec.ScalarMul("ients[0], &points[0]) + foldedPointsQuotients = *v.ec.ScalarMul("ients[0], &randomNumbers[0]) for i := 1; i < len(digests); i++ { - tmp = v.ec.ScalarMul("ients[i], &points[i]) + tmp = v.ec.ScalarMul("ients[i], &randomNumbers[i]) foldedPointsQuotients = *v.ec.Add(&foldedPointsQuotients, tmp) } @@ -270,6 +273,32 @@ func (v *Verifier[S, G1El, G2El, GTEl]) BatchVerifyMultiPoints(digests []Commitm return err } +func (v *Verifier[S, G1El, G2El, GTEl]) fold(digests []Commitment[G1El], fai, ci []emulated.Element[S]) (Commitment[G1El], emulated.Element[S]) { + + // length inconsistency between digests and evaluations should have been done before calling this function + nbDigests := len(digests) + + // fold the claimed values ∑ᵢcᵢf(aᵢ) + var foldedEvaluations, tmp emulated.Element[S] + foldedEvaluations = emulated.ValueOf[S](0) + for i := 0; i < nbDigests; i++ { + tmp = *v.scalarApi.Mul(&fai[i], &ci[i]) + foldedEvaluations = *v.scalarApi.Add(&foldedEvaluations, &tmp) + } + + // fold the digests ∑ᵢ[cᵢ]([fᵢ(α)]G₁) + var foldedDigests Commitment[G1El] + foldedDigests.G1El = *v.ec.ScalarMul(&digests[0].G1El, &ci[0]) + for i := 1; i < nbDigests; i++ { + tmp := *v.ec.ScalarMul(&digests[i].G1El, &ci[i]) + foldedDigests.G1El = *v.ec.Add(&tmp, &foldedDigests.G1El) + } + + // folding done + return foldedDigests, foldedEvaluations + +} + // deriveGamma derives a challenge using Fiat Shamir to fold proofs. // dataTranscript are supposed to be bits. // /!\ bitMode = true here /!\ diff --git a/std/commitments/kzg_refactor/verifier_test.go b/std/commitments/kzg_refactor/verifier_test.go index c0f251f3f2..e8dba0615a 100644 --- a/std/commitments/kzg_refactor/verifier_test.go +++ b/std/commitments/kzg_refactor/verifier_test.go @@ -319,8 +319,11 @@ func TestBatchVerifySinglePoint(t *testing.T) { assert.NoError(err) } + // random point at which the polynomials are evaluated var point fr_bn254.Element point.SetRandom() + + // build short hash, we pick a number one byte less than the snark field... var target big.Int target.SetUint64(1) nbBits := ecc.BLS12_381.ScalarField().BitLen() @@ -362,44 +365,35 @@ func TestBatchVerifySinglePoint(t *testing.T) { } //-------------------------------------------------------- -// derive gamma +// Batch verify multi point + +// type BatchVerifyMultiPointsTest[S emulated.FieldParams, G1El, G2El, GTEl any] struct { +// Vk VerifyingKey[G1El, G2El] +// Digests [5]Commitment[G1El] +// Proofs [5]OpeningProof[S, G1El] +// Points [5]emulated.Element[S] +// } -type DeriveGammaTest[S emulated.FieldParams, G1El, G2El, GTEl any] struct { - Point emulated.Element[S] - Digests [10]Commitment[G1El] - ClaimedValues [10]emulated.Element[S] - Gamma emulated.Element[S] +type BatchVerifyMultiPointsTest[S emulated.FieldParams, G1El, G2El, GTEl any] struct { + Vk VerifyingKey[G1El, G2El] + Digests [2]Commitment[G1El] + Proofs [2]OpeningProof[S, G1El] + Points [2]emulated.Element[S] } -func (circuit *DeriveGammaTest[S, G1El, G2El, GTEl]) Define(api frontend.API) error { +func (circuit *BatchVerifyMultiPointsTest[S, G1El, G2El, GTEl]) Define(api frontend.API) error { verifier, err := NewVerifier[S, G1El, G2El, GTEl](api) if err != nil { return fmt.Errorf("get pairing: %w", err) } - // pick a number on byte shorter than the modulus size - var target big.Int - target.SetUint64(1) - nbBits := api.Compiler().Field().BitLen() - nn := ((nbBits+7)/8)*8 - 8 - target.Lsh(&target, uint(nn)) - - // create the wrapped hash function - whSnark, err := recursion.NewHash(api, &target, true) - if err != nil { - return err - } + verifier.BatchVerifyMultiPoints(circuit.Digests[:], circuit.Proofs[:], circuit.Points[:], circuit.Vk) - res, err := verifier.deriveGamma(circuit.Point, circuit.Digests[:], circuit.ClaimedValues[:], whSnark) - if err != nil { - return err - } - verifier.scalarApi.AssertIsEqual(&res, &circuit.Gamma) return nil } -func TestDeriveGamma(t *testing.T) { +func TestBatchVerifyMultiPoints(t *testing.T) { assert := test.NewAssert(t) @@ -409,55 +403,158 @@ func TestDeriveGamma(t *testing.T) { srs, err := kzg_bn254.NewSRS(kzgSize, alpha) assert.NoError(err) - var polynomials [10][]fr_bn254.Element - var digests [10]kzg_bn254.Digest - for i := 0; i < 10; i++ { + var polynomials [2][]fr_bn254.Element + var coms [2]kzg_bn254.Digest + for i := 0; i < 2; i++ { polynomials[i] = make([]fr_bn254.Element, polynomialSize) for j := 0; j < polynomialSize; j++ { polynomials[i][j].SetRandom() } - digests[i], err = kzg_bn254.Commit(polynomials[i], srs.Pk) + coms[i], err = kzg_bn254.Commit(polynomials[i], srs.Pk) assert.NoError(err) } - var point fr_bn254.Element - point.SetRandom() - var target big.Int - target.SetUint64(1) - nbBits := ecc.BLS12_381.ScalarField().BitLen() - nn := ((nbBits+7)/8)*8 - 8 - target.Lsh(&target, uint(nn)) - h, err := recursion.NewShort(ecc.BLS12_381.ScalarField(), &target) - assert.NoError(err) + // random points at which the polynomials are evaluated + var points [2]fr_bn254.Element + for i := 0; i < 2; i++ { + points[i].SetRandom() + } - batchOpeningProof, err := kzg_bn254.BatchOpenSinglePoint(polynomials[:], digests[:], point, h, srs.Pk) - assert.NoError(err) + // build opening proofs + var openingProofs [2]kzg_bn254.OpeningProof + for i := 0; i < 2; i++ { + openingProofs[i], err = kzg_bn254.Open(polynomials[i], points[i], srs.Pk) + assert.NoError(err) + } - gamma, err := kzg_bn254.DeriveGamma(point, digests[:], batchOpeningProof.ClaimedValues, h) + // check that the proofs are correct + err = kzg_bn254.BatchVerifyMultiPoints(coms[:], openingProofs[:], points[:], srs.Vk) assert.NoError(err) // prepare witness - wPoint, err := ValueOfScalar[emulated.BN254Fr](point) + wVk, err := ValueOfVerifyingKey[sw_bn254.G1Affine, sw_bn254.G2Affine](srs.Vk) assert.NoError(err) - var wDigests [10]Commitment[sw_bn254.G1Affine] - for i := 0; i < 10; i++ { - wDigests[i], err = ValueOfCommitment[sw_bn254.G1Affine](digests[i]) + var wDigests [2]Commitment[sw_bn254.G1Affine] + var wPoints [2]emulated.Element[emulated.BN254Fr] + var wOpeningProofs [2]OpeningProof[emulated.BN254Fr, sw_bn254.G1Affine] + for i := 0; i < 2; i++ { + wPoints[i], err = ValueOfScalar[emulated.BN254Fr](points[i]) assert.NoError(err) - } - var wClaimedValues [10]emulated.Element[emulated.BN254Fr] - for i := 0; i < 10; i++ { - wClaimedValues[i], err = ValueOfScalar[emulated.BN254Fr](batchOpeningProof.ClaimedValues[i]) + wDigests[i], err = ValueOfCommitment[sw_bn254.G1Affine](coms[i]) + assert.NoError(err) + wOpeningProofs[i], err = ValueOfOpeningProof[emulated.BN254Fr, sw_bn254.G1Affine](openingProofs[i]) assert.NoError(err) } - wGmma, err := ValueOfScalar[emulated.BN254Fr](gamma) - assert.NoError(err) - assignment := DeriveGammaTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ - Point: wPoint, - Digests: wDigests, - ClaimedValues: wClaimedValues, - Gamma: wGmma, + assignment := BatchVerifyMultiPointsTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ + Vk: wVk, + Points: wPoints, + Digests: wDigests, + Proofs: wOpeningProofs, } - assert.CheckCircuit(&DeriveGammaTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{}, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) + var circuit BatchVerifyMultiPointsTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl] + assert.CheckCircuit(&circuit, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) + } + +//-------------------------------------------------------- +// derive gamma + +// type DeriveGammaTest[S emulated.FieldParams, G1El, G2El, GTEl any] struct { +// Point emulated.Element[S] +// Digests [10]Commitment[G1El] +// ClaimedValues [10]emulated.Element[S] +// Gamma emulated.Element[S] +// } + +// func (circuit *DeriveGammaTest[S, G1El, G2El, GTEl]) Define(api frontend.API) error { + +// verifier, err := NewVerifier[S, G1El, G2El, GTEl](api) +// if err != nil { +// return fmt.Errorf("get pairing: %w", err) +// } + +// // pick a number on byte shorter than the modulus size +// var target big.Int +// target.SetUint64(1) +// nbBits := api.Compiler().Field().BitLen() +// nn := ((nbBits+7)/8)*8 - 8 +// target.Lsh(&target, uint(nn)) + +// // create the wrapped hash function +// whSnark, err := recursion.NewHash(api, &target, true) +// if err != nil { +// return err +// } + +// res, err := verifier.deriveGamma(circuit.Point, circuit.Digests[:], circuit.ClaimedValues[:], whSnark) +// if err != nil { +// return err +// } +// verifier.scalarApi.AssertIsEqual(&res, &circuit.Gamma) +// return nil +// } + +// func TestDeriveGamma(t *testing.T) { + +// assert := test.NewAssert(t) + +// // prepare test data +// alpha, err := rand.Int(rand.Reader, ecc.BN254.ScalarField()) +// assert.NoError(err) +// srs, err := kzg_bn254.NewSRS(kzgSize, alpha) +// assert.NoError(err) + +// var polynomials [10][]fr_bn254.Element +// var digests [10]kzg_bn254.Digest +// for i := 0; i < 10; i++ { +// polynomials[i] = make([]fr_bn254.Element, polynomialSize) +// for j := 0; j < polynomialSize; j++ { +// polynomials[i][j].SetRandom() +// } +// digests[i], err = kzg_bn254.Commit(polynomials[i], srs.Pk) +// assert.NoError(err) +// } + +// var point fr_bn254.Element +// point.SetRandom() +// var target big.Int +// target.SetUint64(1) +// nbBits := ecc.BLS12_381.ScalarField().BitLen() +// nn := ((nbBits+7)/8)*8 - 8 +// target.Lsh(&target, uint(nn)) +// h, err := recursion.NewShort(ecc.BLS12_381.ScalarField(), &target) +// assert.NoError(err) + +// batchOpeningProof, err := kzg_bn254.BatchOpenSinglePoint(polynomials[:], digests[:], point, h, srs.Pk) +// assert.NoError(err) + +// gamma, err := kzg_bn254.DeriveGamma(point, digests[:], batchOpeningProof.ClaimedValues, h) +// assert.NoError(err) + +// // prepare witness +// wPoint, err := ValueOfScalar[emulated.BN254Fr](point) +// assert.NoError(err) +// var wDigests [10]Commitment[sw_bn254.G1Affine] +// for i := 0; i < 10; i++ { +// wDigests[i], err = ValueOfCommitment[sw_bn254.G1Affine](digests[i]) +// assert.NoError(err) +// } +// var wClaimedValues [10]emulated.Element[emulated.BN254Fr] +// for i := 0; i < 10; i++ { +// wClaimedValues[i], err = ValueOfScalar[emulated.BN254Fr](batchOpeningProof.ClaimedValues[i]) +// assert.NoError(err) +// } +// wGmma, err := ValueOfScalar[emulated.BN254Fr](gamma) +// assert.NoError(err) + +// assignment := DeriveGammaTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ +// Point: wPoint, +// Digests: wDigests, +// ClaimedValues: wClaimedValues, +// Gamma: wGmma, +// } + +// assert.CheckCircuit(&DeriveGammaTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{}, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) +// } From 059a3e3e8501d4fd92f3ccc18fde3bc8e260683e Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Tue, 7 Nov 2023 12:46:21 +0100 Subject: [PATCH 13/15] feat: kzg_refactor/ -> kzg/ --- .../{kzg_refactor => kzg}/conversion.go | 2 +- std/commitments/kzg/native_doc_test.go | 128 ---- std/commitments/kzg/nonnative_doc_test.go | 151 ---- std/commitments/kzg/verifier.go | 513 +++++++------ std/commitments/kzg/verifier_test.go | 699 +++++++++++------- std/commitments/kzg_refactor/verifier.go | 337 --------- std/commitments/kzg_refactor/verifier_test.go | 560 -------------- 7 files changed, 717 insertions(+), 1673 deletions(-) rename std/commitments/{kzg_refactor => kzg}/conversion.go (99%) delete mode 100644 std/commitments/kzg/native_doc_test.go delete mode 100644 std/commitments/kzg/nonnative_doc_test.go delete mode 100644 std/commitments/kzg_refactor/verifier.go delete mode 100644 std/commitments/kzg_refactor/verifier_test.go diff --git a/std/commitments/kzg_refactor/conversion.go b/std/commitments/kzg/conversion.go similarity index 99% rename from std/commitments/kzg_refactor/conversion.go rename to std/commitments/kzg/conversion.go index 1bbae7ea0d..71ea4269bb 100644 --- a/std/commitments/kzg_refactor/conversion.go +++ b/std/commitments/kzg/conversion.go @@ -1,4 +1,4 @@ -package kzg_refactor +package kzg import ( "fmt" diff --git a/std/commitments/kzg/native_doc_test.go b/std/commitments/kzg/native_doc_test.go deleted file mode 100644 index 8a183e8a66..0000000000 --- a/std/commitments/kzg/native_doc_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package kzg_test - -import ( - "crypto/rand" - - "github.com/consensys/gnark-crypto/ecc" - fr_bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" - kzg_bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377/kzg" - "github.com/consensys/gnark/backend/groth16" - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/algebra/native/sw_bls12377" - "github.com/consensys/gnark/std/commitments/kzg" -) - -// Example of using KZG verifier using 2-chains of curves. It is significantly -// more efficient than using field emulation, but requires a specific chain of -// inner and outer curves. -func Example_native() { - // !!! UNSAFE SRS. FOR EXAMPLE PURPOSES ONLY. We create a trusted SRS for - // KZG polynomial commitment scheme. In practice this must be prepared using - // MPC or by reusing existing SRS. !!! - - const ( - // size of the SRS. Defines the maximum degree of the polynomial which can be committed to - kzgSize = 128 - // degree of the random polynomial in the example - polynomialSize = 100 - ) - - // create new SRS for example purposes (NB! UNSAFE!) - alpha, err := rand.Int(rand.Reader, ecc.BLS12_377.ScalarField()) - if err != nil { - panic("sampling alpha failed: " + err.Error()) - } - srs, err := kzg_bls12377.NewSRS(kzgSize, alpha) // UNSAFE! - if err != nil { - panic("new SRS failed: " + err.Error()) - } - - // sample the random polynomial by sampling the coefficients. - f := make([]fr_bls12377.Element, polynomialSize) - for i := range f { - f[i].SetRandom() - } - - // natively commit to the polynomial using SRS - com, err := kzg_bls12377.Commit(f, srs.Pk) - if err != nil { - panic("commitment failed: " + err.Error()) - } - - // sample random evaluation point - var point fr_bls12377.Element - point.SetRandom() - - // construct a proof of correct opening. The evaluation value is proof.ClaimedValue - proof, err := kzg_bls12377.Open(f, point, srs.Pk) - if err != nil { - panic("test opening failed: " + err.Error()) - } - - // test opening proof natively - if err = kzg_bls12377.Verify(&com, &proof, point, srs.Vk); err != nil { - panic("test verify failed: " + err.Error()) - } - - // create a witness element of the commitment - wCmt, err := kzg.ValueOfCommitment[sw_bls12377.G1Affine](com) - if err != nil { - panic("commitment witness failed: " + err.Error()) - } - - // create a witness element of the opening proof and the evaluation point - wProof, err := kzg.ValueOfOpeningProof[sw_bls12377.Scalar, sw_bls12377.G1Affine](point, proof) - if err != nil { - panic("opening proof witness failed: " + err.Error()) - } - - // create a witness element of the SRS - wVk, err := kzg.ValueOfVerifyingKey[sw_bls12377.G2Affine](srs.Vk) - if err != nil { - panic("verifying key witness failed: " + err.Error()) - } - assignment := KZGVerificationCircuit[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ - VerifyingKey: wVk, - Commitment: wCmt, - OpeningProof: wProof, - } - circuit := KZGVerificationCircuit[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{} - - // because we are using 2-chains then the outer curve must correspond to the - // inner curve. For inner BLS12-377 the outer curve is BW6-761. - ccs, err := frontend.Compile(ecc.BW6_761.ScalarField(), r1cs.NewBuilder, &circuit) - if err != nil { - panic("compile failed: " + err.Error()) - } - - // create Groth16 setup. NB! UNSAFE - pk, vk, err := groth16.Setup(ccs) // UNSAFE! Use MPC - if err != nil { - panic("setup failed: " + err.Error()) - } - - // create prover witness from the assignment - secretWitness, err := frontend.NewWitness(&assignment, ecc.BW6_761.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 groth16 proof of verifying KZG commitment opening in-circuit - circuitProof, err := groth16.Prove(ccs, pk, secretWitness) - if err != nil { - panic("proving failed: " + err.Error()) - } - - // verify the Groth16 proof - err = groth16.Verify(circuitProof, vk, publicWitness) - if err != nil { - panic("circuit verification failed: " + err.Error()) - } -} diff --git a/std/commitments/kzg/nonnative_doc_test.go b/std/commitments/kzg/nonnative_doc_test.go deleted file mode 100644 index 8fd0243a81..0000000000 --- a/std/commitments/kzg/nonnative_doc_test.go +++ /dev/null @@ -1,151 +0,0 @@ -package kzg_test - -import ( - "crypto/rand" - "fmt" - - "github.com/consensys/gnark-crypto/ecc" - fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" - kzg_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/kzg" - "github.com/consensys/gnark/backend/groth16" - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/r1cs" - "github.com/consensys/gnark/std/algebra" - "github.com/consensys/gnark/std/algebra/emulated/sw_bn254" - "github.com/consensys/gnark/std/commitments/kzg" -) - -type KZGVerificationCircuit[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GTEl algebra.GtElementT] struct { - kzg.VerifyingKey[G2El] - kzg.Commitment[G1El] - kzg.OpeningProof[S, G1El] -} - -func (c *KZGVerificationCircuit[S, G1El, G2El, GTEl]) Define(api frontend.API) error { - curve, err := algebra.GetCurve[S, G1El](api) - if err != nil { - return fmt.Errorf("get curve: %w", err) - } - pairing, err := algebra.GetPairing[G1El, G2El, GTEl](api) - if err != nil { - return fmt.Errorf("get pairing: %w", err) - } - verifier := kzg.NewVerifier(c.VerifyingKey, curve, pairing) - if err := verifier.AssertProof(c.Commitment, c.OpeningProof); err != nil { - return fmt.Errorf("assert proof: %w", err) - } - return nil -} - -// Example of using KZG verifier using emulated pairing implementation. -func Example_emulated() { - // !!! UNSAFE SRS. FOR EXAMPLE PURPOSES ONLY. We create a trusted SRS for - // KZG polynomial commitment scheme. In practice this must be prepared using - // MPC or by reusing existing SRS. !!! - - const ( - // size of the SRS. Defines the maximum degree of the polynomial which can be committed to - kzgSize = 128 - // degree of the random polynomial in the example - polynomialSize = 100 - ) - - // create new SRS for example purposes (NB! UNSAFE!) - alpha, err := rand.Int(rand.Reader, ecc.BN254.ScalarField()) - if err != nil { - panic("sampling alpha failed: " + err.Error()) - } - srs, err := kzg_bn254.NewSRS(kzgSize, alpha) // UNSAFE! - if err != nil { - panic("new SRS failed: " + err.Error()) - } - - // sample the random polynomial by sampling the coefficients. - f := make([]fr_bn254.Element, polynomialSize) - for i := range f { - f[i].SetRandom() - } - - // natively commit to the polynomial using SRS - com, err := kzg_bn254.Commit(f, srs.Pk) - if err != nil { - panic("commitment failed: " + err.Error()) - } - - // sample random evaluation point - var point fr_bn254.Element - point.SetRandom() - - // construct a proof of correct opening. The evaluation value is proof.ClaimedValue - proof, err := kzg_bn254.Open(f, point, srs.Pk) - if err != nil { - panic("test opening failed: " + err.Error()) - } - - // test opening proof natively - if err = kzg_bn254.Verify(&com, &proof, point, srs.Vk); err != nil { - panic("test verify failed: " + err.Error()) - } - - // create a witness element of the commitment - wCmt, err := kzg.ValueOfCommitment[sw_bn254.G1Affine](com) - if err != nil { - panic("commitment witness failed: " + err.Error()) - } - - // create a witness element of the opening proof and the evaluation point - wProof, err := kzg.ValueOfOpeningProof[sw_bn254.Scalar, sw_bn254.G1Affine](point, proof) - if err != nil { - panic("opening proof witness failed: " + err.Error()) - } - - // create a witness element of the SRS - wVk, err := kzg.ValueOfVerifyingKey[sw_bn254.G2Affine](srs.Vk) - if err != nil { - panic("verifying key witness failed: " + err.Error()) - } - assignment := KZGVerificationCircuit[sw_bn254.Scalar, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ - VerifyingKey: wVk, - Commitment: wCmt, - OpeningProof: wProof, - } - circuit := KZGVerificationCircuit[sw_bn254.Scalar, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{} - - // as we are currently using the emulated implementation of BN254 - // in-circuit, then we can compile to any curve. For example purposes, here - // we use BN254. - ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit) - if err != nil { - panic("compile failed: " + err.Error()) - } - - // create Groth16 setup. NB! UNSAFE - pk, vk, err := groth16.Setup(ccs) // UNSAFE! Use MPC - if err != nil { - panic("setup failed: " + err.Error()) - } - - // create prover witness from the assignment - secretWitness, err := frontend.NewWitness(&assignment, 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 groth16 proof of verifying KZG commitment opening in-circuit - circuitProof, err := groth16.Prove(ccs, pk, secretWitness) - if err != nil { - panic("proving failed: " + err.Error()) - } - - // verify the Groth16 proof - err = groth16.Verify(circuitProof, vk, publicWitness) - if err != nil { - panic("circuit verification failed: " + err.Error()) - } -} diff --git a/std/commitments/kzg/verifier.go b/std/commitments/kzg/verifier.go index 7d71ee5115..0ab2d5fe8d 100644 --- a/std/commitments/kzg/verifier.go +++ b/std/commitments/kzg/verifier.go @@ -1,264 +1,337 @@ -// Package kzg implements KZG polynomial commitment verification. -// -// KZG polynomial commitment allows for the prover to commit to a polynomial and -// then selectively prove evaluations of the said polynomial. The size of the -// commitment is a single G1 element and the size of the evaluation proof is -// also a single G1 element. However, KZG polynomial commitment scheme requires -// a trusted SRS. -// -// This package supersedes previous type-specific implementations and allows to -// use any implemented pairing-friendly curve implementation, being defined over -// a 2-chain (native implementation) or using field emulation. package kzg import ( + "errors" "fmt" - bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377" - fr_bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" - kzg_bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377/kzg" - bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" - fr_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" - kzg_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/kzg" - bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315" - fr_bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" - kzg_bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315/kzg" - "github.com/consensys/gnark-crypto/ecc/bn254" - fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" - kzg_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/kzg" - bw6761 "github.com/consensys/gnark-crypto/ecc/bw6-761" - fr_bw6761 "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" - kzg_bw6761 "github.com/consensys/gnark-crypto/ecc/bw6-761/kzg" + "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/emulated/sw_bw6761" - "github.com/consensys/gnark/std/algebra/native/sw_bls12377" - "github.com/consensys/gnark/std/algebra/native/sw_bls24315" + fiatshamir "github.com/consensys/gnark/std/fiat-shamir" + "github.com/consensys/gnark/std/hash" + "github.com/consensys/gnark/std/math/emulated" +) + +var ( + ErrInvalidNbDigests = errors.New("number of digests is not the same as the number of polynomials") + ErrZeroNbDigests = errors.New("number of digests is zero") ) // Commitment is an KZG commitment to a polynomial. Use [ValueOfCommitment] to // initialize a witness from the native commitment. -type Commitment[G1El algebra.G1ElementT] struct { +type Commitment[G1El any] struct { G1El G1El } -// ValueOfCommitment initializes a KZG commitment witness from a native -// commitment. It returns an error if there is a conflict between the type -// parameters and provided native commitment type. -func ValueOfCommitment[G1El algebra.G1ElementT](cmt any) (Commitment[G1El], error) { - var ret Commitment[G1El] - switch s := any(&ret).(type) { - case *Commitment[sw_bn254.G1Affine]: - tCmt, ok := cmt.(bn254.G1Affine) - if !ok { - return ret, fmt.Errorf("mismatching types %T %T", ret, cmt) - } - s.G1El = sw_bn254.NewG1Affine(tCmt) - case *Commitment[sw_bls12377.G1Affine]: - tCmt, ok := cmt.(bls12377.G1Affine) - if !ok { - return ret, fmt.Errorf("mismatching types %T %T", ret, cmt) - } - s.G1El = sw_bls12377.NewG1Affine(tCmt) - case *Commitment[sw_bls12381.G1Affine]: - tCmt, ok := cmt.(bls12381.G1Affine) - if !ok { - return ret, fmt.Errorf("mismatching types %T %T", ret, cmt) - } - s.G1El = sw_bls12381.NewG1Affine(tCmt) - case *Commitment[sw_bw6761.G1Affine]: - tCmt, ok := cmt.(bw6761.G1Affine) - if !ok { - return ret, fmt.Errorf("mismatching types %T %T", ret, cmt) - } - s.G1El = sw_bw6761.NewG1Affine(tCmt) - case *Commitment[sw_bls24315.G1Affine]: - tCmt, ok := cmt.(bls24315.G1Affine) - if !ok { - return ret, fmt.Errorf("mismatching types %T %T", ret, cmt) - } - s.G1El = sw_bls24315.NewG1Affine(tCmt) - default: - return ret, fmt.Errorf("unknown type parametrization") - } - return ret, nil -} - // OpeningProof embeds the opening proof that polynomial evaluated at Point is // equal to ClaimedValue. Use [ValueOfOpeningProof] to initialize a witness from // a native opening proof. -type OpeningProof[S algebra.ScalarT, G1El algebra.G1ElementT] struct { - QuotientPoly G1El - ClaimedValue S - Point S -} - -// ValueOfOpeningProof initializes an opening proof from the given proof and -// point. It returns an error if there is a mismatch between the type parameters -// and types of the provided point and proof. -func ValueOfOpeningProof[S algebra.ScalarT, G1El algebra.G1ElementT](point any, proof any) (OpeningProof[S, G1El], error) { - var ret OpeningProof[S, G1El] - switch s := any(&ret).(type) { - case *OpeningProof[sw_bn254.Scalar, sw_bn254.G1Affine]: - tProof, ok := proof.(kzg_bn254.OpeningProof) - if !ok { - return ret, fmt.Errorf("mismatching types %T %T", ret, proof) - } - tPoint, ok := point.(fr_bn254.Element) - if !ok { - return ret, fmt.Errorf("mismatching types %T %T", ret, point) - } - s.QuotientPoly = sw_bn254.NewG1Affine(tProof.H) - s.ClaimedValue = sw_bn254.NewScalar(tProof.ClaimedValue) - s.Point = sw_bn254.NewScalar(tPoint) - case *OpeningProof[sw_bls12377.Scalar, sw_bls12377.G1Affine]: - tProof, ok := proof.(kzg_bls12377.OpeningProof) - if !ok { - return ret, fmt.Errorf("mismatching types %T %T", ret, proof) - } - tPoint, ok := point.(fr_bls12377.Element) - if !ok { - return ret, fmt.Errorf("mismatching types %T %T", ret, point) - } - s.QuotientPoly = sw_bls12377.NewG1Affine(tProof.H) - s.ClaimedValue = tProof.ClaimedValue.String() - s.Point = tPoint.String() - case *OpeningProof[sw_bls12381.Scalar, sw_bls12381.G1Affine]: - tProof, ok := proof.(kzg_bls12381.OpeningProof) - if !ok { - return ret, fmt.Errorf("mismatching types %T %T", ret, proof) - } - tPoint, ok := point.(fr_bls12381.Element) - if !ok { - return ret, fmt.Errorf("mismatching types %T %T", ret, point) - } - s.QuotientPoly = sw_bls12381.NewG1Affine(tProof.H) - s.ClaimedValue = sw_bls12381.NewScalar(tProof.ClaimedValue) - s.Point = sw_bls12381.NewScalar(tPoint) - case *OpeningProof[sw_bw6761.Scalar, sw_bw6761.G1Affine]: - tProof, ok := proof.(kzg_bw6761.OpeningProof) - if !ok { - return ret, fmt.Errorf("mismatching types %T %T", ret, proof) - } - tPoint, ok := point.(fr_bw6761.Element) - if !ok { - return ret, fmt.Errorf("mismatching types %T %T", ret, point) - } - s.QuotientPoly = sw_bw6761.NewG1Affine(tProof.H) - s.ClaimedValue = sw_bw6761.NewScalar(tProof.ClaimedValue) - s.Point = sw_bw6761.NewScalar(tPoint) - case *OpeningProof[sw_bls24315.Scalar, sw_bls24315.G1Affine]: - tProof, ok := proof.(kzg_bls24315.OpeningProof) - if !ok { - return ret, fmt.Errorf("mismatching types %T %T", ret, proof) - } - tPoint, ok := point.(fr_bls24315.Element) - if !ok { - return ret, fmt.Errorf("mismatching types %T %T", ret, point) - } - s.QuotientPoly = sw_bls24315.NewG1Affine(tProof.H) - s.ClaimedValue = tProof.ClaimedValue.String() - s.Point = tPoint.String() - default: - return ret, fmt.Errorf("unknown type parametrization") - } - return ret, nil +type OpeningProof[S emulated.FieldParams, G1El any] struct { + Quotient G1El + ClaimedValue emulated.Element[S] } // VerifyingKey is the trusted setup for KZG polynomial commitment scheme. Use // [ValueOfVerifyingKey] to initialize a witness from the native VerifyingKey. -type VerifyingKey[G2El algebra.G2ElementT] struct { - SRS [2]G2El +type VerifyingKey[G1El, G2El any] struct { + G2 [2]G2El + G1 G1El } -// ValueOfVerifyingKey initializes verifying key witness from the native -// verifying key. It returns an error if there is a mismatch between the type -// parameters and the provided verifying key type. -func ValueOfVerifyingKey[G2El algebra.G2ElementT](vk any) (VerifyingKey[G2El], error) { - var ret VerifyingKey[G2El] - switch s := any(&ret).(type) { - case *VerifyingKey[sw_bn254.G2Affine]: - tVk, ok := vk.(kzg_bn254.VerifyingKey) - if !ok { - return ret, fmt.Errorf("mismatching types %T %T", ret, vk) - } - s.SRS[0] = sw_bn254.NewG2Affine(tVk.G2[0]) - s.SRS[1] = sw_bn254.NewG2Affine(tVk.G2[1]) - case *VerifyingKey[sw_bls12377.G2Affine]: - tVk, ok := vk.(kzg_bls12377.VerifyingKey) - if !ok { - return ret, fmt.Errorf("mismatching types %T %T", ret, vk) - } - s.SRS[0] = sw_bls12377.NewG2Affine(tVk.G2[0]) - s.SRS[1] = sw_bls12377.NewG2Affine(tVk.G2[1]) - case *VerifyingKey[sw_bls12381.G2Affine]: - tVk, ok := vk.(kzg_bls12381.VerifyingKey) - if !ok { - return ret, fmt.Errorf("mismatching types %T %T", ret, vk) - } - s.SRS[0] = sw_bls12381.NewG2Affine(tVk.G2[0]) - s.SRS[1] = sw_bls12381.NewG2Affine(tVk.G2[1]) - case *VerifyingKey[sw_bw6761.G2Affine]: - tVk, ok := vk.(kzg_bw6761.VerifyingKey) - if !ok { - return ret, fmt.Errorf("mismatching types %T %T", ret, vk) - } - s.SRS[0] = sw_bw6761.NewG2Affine(tVk.G2[0]) - s.SRS[1] = sw_bw6761.NewG2Affine(tVk.G2[1]) - case *VerifyingKey[sw_bls24315.G2Affine]: - tVk, ok := vk.(kzg_bls24315.VerifyingKey) - if !ok { - return ret, fmt.Errorf("mismatching types %T %T", ret, vk) - } - s.SRS[0] = sw_bls24315.NewG2Affine(tVk.G2[0]) - s.SRS[1] = sw_bls24315.NewG2Affine(tVk.G2[1]) - default: - return ret, fmt.Errorf("unknown type parametrization") - } - return ret, nil +type BatchOpeningProof[S emulated.FieldParams, G1El any] struct { + Quotient G1El + ClaimedValues []emulated.Element[S] } -// Verifier allows verifying KZG opening proofs. -type Verifier[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.G2ElementT] struct { - VerifyingKey[G2El] +// B base field, S scalar +// S here is emulated.Element[S] +type IVerifier[S emulated.FieldParams, G1El, G2El any] interface { + CheckOpeningProof(Commitment[G1El], OpeningProof[S, G1El], emulated.Element[S], VerifyingKey[G1El, G2El]) error + FoldProof([]Commitment[G1El], BatchOpeningProof[S, G1El], emulated.Element[S], hash.FieldHasher, ...frontend.Variable) (OpeningProof[S, G1El], Commitment[G1El], error) + BatchVerifySinglePoint([]Commitment[G1El], BatchOpeningProof[S, G1El], emulated.Element[S], VerifyingKey[G1El, G2El], hash.FieldHasher, ...frontend.Variable) error + BatchVerifyMultiPoints([]Commitment[G1El], []OpeningProof[S, G1El], []emulated.Element[S], VerifyingKey[G1El, G2El]) error +} - curve algebra.Curve[S, G1El] - pairing algebra.Pairing[G1El, G2El, GtEl] +type Verifier[S emulated.FieldParams, G1El, G2El, GtEl any] struct { + api frontend.API + scalarApi *emulated.Field[S] + ec algebra.Curve[emulated.Element[S], G1El] + pairing algebra.Pairing[G1El, G2El, GtEl] } -// NewVerifier initializes a new Verifier instance. -func NewVerifier[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.G2ElementT](vk VerifyingKey[G2El], curve algebra.Curve[S, G1El], pairing algebra.Pairing[G1El, G2El, GtEl]) *Verifier[S, G1El, G2El, GtEl] { - return &Verifier[S, G1El, G2El, GtEl]{ - VerifyingKey: vk, - curve: curve, - pairing: pairing, +func NewVerifier[S emulated.FieldParams, G1El, G2El, GtEl any](api frontend.API) (Verifier[S, G1El, G2El, GtEl], error) { + var res Verifier[S, G1El, G2El, GtEl] + var err error + res.api = api + res.ec, err = algebra.GetCurve[emulated.Element[S], G1El](api) + if err != nil { + return res, err + } + res.scalarApi, err = emulated.NewField[S](api) + if err != nil { + return res, err } + res.pairing, err = algebra.GetPairing[G1El, G2El, GtEl](api) + if err != nil { + return res, err + } + + return res, nil } -// AssertProof asserts the validity of the opening proof for the given -// commitment. -func (vk *Verifier[S, G1El, G2El, GtEl]) AssertProof(commitment Commitment[G1El], proof OpeningProof[S, G1El]) error { - // [f(a)]G₁ - claimedValueG1 := vk.curve.ScalarMulBase(&proof.ClaimedValue) +// S here is emulated.FieldParams +func (v *Verifier[S, G1El, G2El, GTEl]) CheckOpeningProof(digest Commitment[G1El], proof OpeningProof[S, G1El], point emulated.Element[S], vk VerifyingKey[G1El, G2El]) error { + + claimedValueG1 := v.ec.ScalarMulBase(&proof.ClaimedValue) // [f(α) - f(a)]G₁ - fminusfaG1 := vk.curve.Neg(claimedValueG1) - fminusfaG1 = vk.curve.Add(fminusfaG1, &commitment.G1El) + fminusfaG1 := v.ec.Neg(claimedValueG1) + fminusfaG1 = v.ec.Add(fminusfaG1, &digest.G1El) // [-H(α)]G₁ - negQuotientPoly := vk.curve.Neg(&proof.QuotientPoly) + negQuotientPoly := v.ec.Neg(&proof.Quotient) // [f(α) - f(a) + a*H(α)]G₁ - totalG1 := vk.curve.ScalarMul(&proof.QuotientPoly, &proof.Point) - totalG1 = vk.curve.Add(totalG1, fminusfaG1) + totalG1 := v.ec.ScalarMul(&proof.Quotient, &point) + totalG1 = v.ec.Add(totalG1, fminusfaG1) // e([f(α)-f(a)+aH(α)]G₁], G₂).e([-H(α)]G₁, [α]G₂) == 1 - if err := vk.pairing.PairingCheck( + if err := v.pairing.PairingCheck( []*G1El{totalG1, negQuotientPoly}, - []*G2El{&vk.SRS[0], &vk.SRS[1]}, + []*G2El{&vk.G2[0], &vk.G2[1]}, ); err != nil { return fmt.Errorf("pairing check: %w", err) } return nil + +} + +func (v *Verifier[S, G1El, G2El, GTEl]) FoldProof(digests []Commitment[G1El], batchOpeningProof BatchOpeningProof[S, G1El], point emulated.Element[S], hf hash.FieldHasher, dataTranscript ...frontend.Variable) (OpeningProof[S, G1El], Commitment[G1El], error) { + + nbDigests := len(digests) + + // check consistency between numbers of claims vs number of digests + if nbDigests != len(batchOpeningProof.ClaimedValues) { + return OpeningProof[S, G1El]{}, Commitment[G1El]{}, ErrInvalidNbDigests + } + + // derive the challenge γ, binded to the point and the commitments + gamma, err := v.deriveGamma(point, digests, batchOpeningProof.ClaimedValues, hf, dataTranscript...) + if err != nil { + return OpeningProof[S, G1El]{}, Commitment[G1El]{}, err + } + + // fold the claimed values and digests + // gammai = [1,γ,γ²,..,γⁿ⁻¹] + gammai := make([]emulated.Element[S], nbDigests) + gammai[0] = emulated.ValueOf[S](1) + if nbDigests > 1 { + gammai[1] = gamma + } + for i := 2; i < nbDigests; i++ { + gammai[i] = *(v.scalarApi.Mul(&gammai[i-1], &gamma)) + } + + foldedDigests, foldedEvaluations := v.fold(digests, batchOpeningProof.ClaimedValues, gammai) + + var foldedProof OpeningProof[S, G1El] + foldedProof.Quotient = batchOpeningProof.Quotient + foldedProof.ClaimedValue = foldedEvaluations + return foldedProof, foldedDigests, nil + + // create the folded opening proof + // var res OpeningProof[S, G1El] + // res.ClaimedValue = batchOpeningProof.ClaimedValues[0] + // res.Quotient = batchOpeningProof.Quotient + // return res, digests[0], nil + +} + +func (v *Verifier[S, G1El, G2El, GTEl]) BatchVerifySinglePoint(digests []Commitment[G1El], batchOpeningProof BatchOpeningProof[S, G1El], point emulated.Element[S], hf hash.FieldHasher, vk VerifyingKey[G1El, G2El], dataTranscript ...frontend.Variable) error { + + // fold the proof + foldedProof, foldedDigest, err := v.FoldProof(digests, batchOpeningProof, point, hf, dataTranscript...) + if err != nil { + return err + } + + // verify the foldedProof against the foldedDigest + err = v.CheckOpeningProof(foldedDigest, foldedProof, point, vk) + + return err +} + +func (v *Verifier[S, G1El, G2El, GTEl]) BatchVerifyMultiPoints(digests []Commitment[G1El], proofs []OpeningProof[S, G1El], points []emulated.Element[S], vk VerifyingKey[G1El, G2El]) error { + + // check consistency nb proogs vs nb digests + if len(digests) != len(proofs) || len(digests) != len(points) { + return ErrInvalidNbDigests + } + + // len(digests) should be nonzero because of randomNumbers + if len(digests) == 0 { + return ErrZeroNbDigests + } + + // if only one digest, call Verify + if len(digests) == 1 { + return v.CheckOpeningProof(digests[0], proofs[0], points[0], vk) + } + + // sample random numbers λᵢ for sampling + randomNumbers := make([]emulated.Element[S], len(digests)) + randomNumbers[0] = emulated.ValueOf[S](1) + for i := 1; i < len(randomNumbers); i++ { + // TODO use real random numbers, follow the solidity smart contract to know which variables are used as seed + randomNumbers[i] = emulated.ValueOf[S](42) + } + + // fold the committed quotients compute ∑ᵢλᵢ[Hᵢ(α)]G₁ + var foldedQuotients G1El + quotients := make([]G1El, len(proofs)) + for i := 0; i < len(randomNumbers); i++ { + quotients[i] = proofs[i].Quotient + } + foldedQuotients = *v.ec.ScalarMul("ients[0], &randomNumbers[0]) + for i := 1; i < len(digests); i++ { + tmp := *v.ec.ScalarMul("ients[i], &randomNumbers[i]) + foldedQuotients = *v.ec.Add(&tmp, &foldedQuotients) + } + // aa := v.ec.MarshalG1(foldedQuotients) + // slices.Reverse(aa[:256]) + // slices.Reverse(aa[256:]) + // xx := v.api.FromBinary(aa[:256]...) + // yy := v.api.FromBinary(aa[256:]...) + // v.api.Println(xx) + // v.api.Println(yy) + + // fold digests and evals + evals := make([]emulated.Element[S], len(digests)) + + // fold the digests: ∑ᵢλᵢ[f_i(α)]G₁ + // fold the evals : ∑ᵢλᵢfᵢ(aᵢ) + for i := 0; i < len(digests); i++ { + + evals[i] = proofs[i].ClaimedValue + + // aa := v.scalarApi.ToBits(&proofs[i].ClaimedValue) + // bb := v.api.FromBinary(aa...) + // v.api.Println(bb) + } + foldedDigests, foldedEvals := v.fold(digests, evals, randomNumbers) + + // bb := v.scalarApi.ToBits(&foldedEvals) + // bbb := v.api.FromBinary(bb...) + // v.api.Println(bbb) + + // aa := v.ec.MarshalG1(foldedDigests.G1El) + // slices.Reverse(aa[:256]) + // slices.Reverse(aa[256:]) + // xx := v.api.FromBinary(aa[:256]...) + // yy := v.api.FromBinary(aa[256:]...) + // v.api.Println(xx) + // v.api.Println(yy) + + // compute commitment to folded Eval [∑ᵢλᵢfᵢ(aᵢ)]G₁ + foldedEvalsCommit := v.ec.ScalarMul(&vk.G1, &foldedEvals) + + // bb := v.scalarApi.ToBits(&foldedEvals) + // bbb := v.api.FromBinary(bb...) + // v.api.Println(bbb) + + // compute foldedDigests = ∑ᵢλᵢ[fᵢ(α)]G₁ - [∑ᵢλᵢfᵢ(aᵢ)]G₁ + // foldedDigests.Sub(&foldedDigests, &foldedEvalsCommit) + tmp := v.ec.Neg(foldedEvalsCommit) + foldedDigests.G1El = *v.ec.Add(&foldedDigests.G1El, tmp) + + // combien the points and the quotients using γᵢ + // ∑ᵢλᵢ[p_i]([Hᵢ(α)]G₁) + var foldedPointsQuotients G1El + for i := 0; i < len(randomNumbers); i++ { + randomNumbers[i] = *v.scalarApi.Mul(&randomNumbers[i], &points[i]) + // randomNumbers[i] = *v.scalarApi.Reduce(&randomNumbers[i]) + } + foldedPointsQuotients = *v.ec.ScalarMul("ients[0], &randomNumbers[0]) + for i := 1; i < len(digests); i++ { + tmp = v.ec.ScalarMul("ients[i], &randomNumbers[i]) + foldedPointsQuotients = *v.ec.Add(&foldedPointsQuotients, tmp) + } + + // ∑ᵢλᵢ[f_i(α)]G₁ - [∑ᵢλᵢfᵢ(aᵢ)]G₁ + ∑ᵢλᵢ[p_i]([Hᵢ(α)]G₁) + // = [∑ᵢλᵢf_i(α) - ∑ᵢλᵢfᵢ(aᵢ) + ∑ᵢλᵢpᵢHᵢ(α)]G₁ + foldedDigests.G1El = *v.ec.Add(&foldedDigests.G1El, &foldedPointsQuotients) + + // -∑ᵢλᵢ[Qᵢ(α)]G₁ + // foldedQuotients.Neg(&foldedQuotients) + foldedQuotients = *v.ec.Neg(&foldedQuotients) + + // pairing check + err := v.pairing.PairingCheck( + []*G1El{&foldedDigests.G1El, &foldedQuotients}, + []*G2El{&vk.G2[0], &vk.G2[1]}, + ) + + return err +} + +func (v *Verifier[S, G1El, G2El, GTEl]) fold(digests []Commitment[G1El], fai, ci []emulated.Element[S]) (Commitment[G1El], emulated.Element[S]) { + + // length inconsistency between digests and evaluations should have been done before calling this function + nbDigests := len(digests) + + // fold the claimed values ∑ᵢcᵢf(aᵢ) + var foldedEvaluations, tmp emulated.Element[S] + foldedEvaluations = emulated.ValueOf[S](0) + for i := 0; i < nbDigests; i++ { + tmp = *v.scalarApi.Mul(&fai[i], &ci[i]) + foldedEvaluations = *v.scalarApi.Add(&foldedEvaluations, &tmp) + } + + // fold the digests ∑ᵢ[cᵢ]([fᵢ(α)]G₁) + var foldedDigests Commitment[G1El] + foldedDigests.G1El = *v.ec.ScalarMul(&digests[0].G1El, &ci[0]) + for i := 1; i < nbDigests; i++ { + tmp := *v.ec.ScalarMul(&digests[i].G1El, &ci[i]) + foldedDigests.G1El = *v.ec.Add(&tmp, &foldedDigests.G1El) + } + + // folding done + return foldedDigests, foldedEvaluations + +} + +// deriveGamma derives a challenge using Fiat Shamir to fold proofs. +// dataTranscript are supposed to be bits. +// /!\ bitMode = true here /!\ +func (v *Verifier[S, G1El, G2El, GTEl]) deriveGamma(point emulated.Element[S], digests []Commitment[G1El], claimedValues []emulated.Element[S], hf hash.FieldHasher, dataTranscript ...frontend.Variable) (emulated.Element[S], error) { + + // derive the challenge gamma, binded to the point and the commitments + fs := fiatshamir.NewTranscript(v.api, hf, "gamma") + + marhsalledPoint := v.ec.MarshalScalar(point) + if err := fs.Bind("gamma", marhsalledPoint); err != nil { + return emulated.Element[S]{}, err + } + for i := range digests { + if err := fs.Bind("gamma", v.ec.MarshalG1(digests[i].G1El)); err != nil { + return emulated.Element[S]{}, err + } + } + for i := range claimedValues { + if err := fs.Bind("gamma", v.ec.MarshalScalar(claimedValues[i])); err != nil { + return emulated.Element[S]{}, err + } + } + + if err := fs.Bind("gamma", dataTranscript); err != nil { + return emulated.Element[S]{}, err + } + + gamma, err := fs.ComputeChallenge("gamma", true) + if err != nil { + return emulated.Element[S]{}, err + } + bGamma := v.api.ToBinary(gamma) + gammaS := v.scalarApi.FromBits(bGamma...) + + return *gammaS, nil } diff --git a/std/commitments/kzg/verifier_test.go b/std/commitments/kzg/verifier_test.go index 2fed4f36f7..d8b85ada45 100644 --- a/std/commitments/kzg/verifier_test.go +++ b/std/commitments/kzg/verifier_test.go @@ -3,31 +3,17 @@ package kzg import ( "crypto/rand" "fmt" + "math/big" "testing" "github.com/consensys/gnark-crypto/ecc" - bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377" - fr_bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" - kzg_bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377/kzg" - bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" - fr_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" - kzg_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/kzg" - bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315" - fr_bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" - kzg_bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315/kzg" - "github.com/consensys/gnark-crypto/ecc/bn254" fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" kzg_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/kzg" - bw6761 "github.com/consensys/gnark-crypto/ecc/bw6-761" - fr_bw6761 "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" - kzg_bw6761 "github.com/consensys/gnark-crypto/ecc/bw6-761/kzg" + "github.com/consensys/gnark/backend" "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/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/emulated" + "github.com/consensys/gnark/std/recursion" "github.com/consensys/gnark/test" ) @@ -36,29 +22,29 @@ const ( polynomialSize = 100 ) -type KZGVerificationCircuit[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GTEl algebra.GtElementT] struct { - VerifyingKey[G2El] - Commitment[G1El] - OpeningProof[S, G1El] +//-------------------------------------------------------- +// Single opening single point + +type KZGVerificationCircuit[S emulated.FieldParams, G1El, G2El, GTEl any] struct { + Vk VerifyingKey[G1El, G2El] + Digest Commitment[G1El] + Proof OpeningProof[S, G1El] + Point emulated.Element[S] } func (c *KZGVerificationCircuit[S, G1El, G2El, GTEl]) Define(api frontend.API) error { - curve, err := algebra.GetCurve[S, G1El](api) - if err != nil { - return fmt.Errorf("get curve: %w", err) - } - pairing, err := algebra.GetPairing[G1El, G2El, GTEl](api) + verifier, err := NewVerifier[S, G1El, G2El, GTEl](api) if err != nil { return fmt.Errorf("get pairing: %w", err) } - verifier := NewVerifier(c.VerifyingKey, curve, pairing) - if err := verifier.AssertProof(c.Commitment, c.OpeningProof); err != nil { + if err := verifier.CheckOpeningProof(c.Digest, c.Proof, c.Point, c.Vk); err != nil { return fmt.Errorf("assert proof: %w", err) } return nil } func TestKZGVerificationEmulated(t *testing.T) { + assert := test.NewAssert(t) alpha, err := rand.Int(rand.Reader, ecc.BN254.ScalarField()) @@ -85,329 +71,490 @@ func TestKZGVerificationEmulated(t *testing.T) { wCmt, err := ValueOfCommitment[sw_bn254.G1Affine](com) assert.NoError(err) - wProof, err := ValueOfOpeningProof[sw_bn254.Scalar, sw_bn254.G1Affine](point, proof) + wProof, err := ValueOfOpeningProof[emulated.BN254Fr, sw_bn254.G1Affine](proof) assert.NoError(err) - wVk, err := ValueOfVerifyingKey[sw_bn254.G2Affine](srs.Vk) + wVk, err := ValueOfVerifyingKey[sw_bn254.G1Affine, sw_bn254.G2Affine](srs.Vk) assert.NoError(err) - assignment := KZGVerificationCircuit[sw_bn254.Scalar, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ - VerifyingKey: wVk, - Commitment: wCmt, - OpeningProof: wProof, + // wPoint, err := ValueOfScalar[emulated.BN254Fr](point) + wPoint, err := ValueOfScalar[emulated.BN254Fr](point) + assert.NoError(err) + + assignment := KZGVerificationCircuit[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ + Vk: wVk, + Digest: wCmt, + Proof: wProof, + Point: wPoint, } - assert.CheckCircuit(&KZGVerificationCircuit[sw_bn254.Scalar, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{}, test.WithValidAssignment(&assignment)) + assert.CheckCircuit(&KZGVerificationCircuit[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{}, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) } -func TestKZGVerificationEmulated2(t *testing.T) { - assert := test.NewAssert(t) +//-------------------------------------------------------- +// Slice proof + +// type SliceTest[S emulated.FieldParams, G1El any] struct { +// Proof BatchOpeningProof[S, G1El] +// } + +// func (circuit *SliceTest[S, G1El]) Define(api frontend.API) error { + +// fmt.Println(len(circuit.Proof.ClaimedValues)) +// return nil +// } + +// func TestSlices(t *testing.T) { + +// assert := test.NewAssert(t) + +// // prepare test data +// alpha, err := rand.Int(rand.Reader, ecc.BN254.ScalarField()) +// assert.NoError(err) +// srs, err := kzg_bn254.NewSRS(kzgSize, alpha) +// assert.NoError(err) + +// var polynomials [10][]fr_bn254.Element +// var coms [10]kzg_bn254.Digest +// for i := 0; i < 10; i++ { +// polynomials[i] = make([]fr_bn254.Element, polynomialSize) +// for j := 0; j < polynomialSize; j++ { +// polynomials[i][j].SetRandom() +// } +// coms[i], err = kzg_bn254.Commit(polynomials[i], srs.Pk) +// assert.NoError(err) +// } + +// var point fr_bn254.Element +// point.SetRandom() +// var target big.Int +// target.SetUint64(1) +// nbBits := ecc.BLS12_381.ScalarField().BitLen() +// nn := ((nbBits+7)/8)*8 - 8 +// target.Lsh(&target, uint(nn)) +// h, err := recursion.NewShort(ecc.BLS12_381.ScalarField(), &target) +// assert.NoError(err) + +// batchOpeningProof, err := kzg_bn254.BatchOpenSinglePoint(polynomials[:], coms[:], point, h, srs.Pk) +// assert.NoError(err) + +// _, _, err = kzg_bn254.FoldProof(coms[:], &batchOpeningProof, point, h) +// assert.NoError(err) + +// // circuit +// var circuit SliceTest[emulated.BN254Fr, sw_bn254.G1Affine] +// circuit.Proof.ClaimedValues = make([]emulated.Element[emulated.BN254Fr], 10) + +// var assignment SliceTest[emulated.BN254Fr, sw_bn254.G1Affine] +// // assignment.Proof.ClaimedValues = make([]emulated.Element[emulated.BN254Fr], 10) +// assignment.Proof, err = ValueOfBatchOpeningProof[emulated.BN254Fr, sw_bn254.G1Affine](batchOpeningProof) +// assert.NoError(err) + +// assert.CheckCircuit(&circuit, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) + +// } + +//-------------------------------------------------------- +// Fold proof + +type FoldProofTest[S emulated.FieldParams, G1El, G2El, GTEl any] struct { + Point emulated.Element[S] + Digests [10]Commitment[G1El] + BatchOpeningProof BatchOpeningProof[S, G1El] + ExpectedFoldedProof OpeningProof[S, G1El] + ExpectedFoldedDigest Commitment[G1El] +} - alpha, err := rand.Int(rand.Reader, ecc.BLS12_381.ScalarField()) - assert.NoError(err) - srs, err := kzg_bls12381.NewSRS(kzgSize, alpha) - assert.NoError(err) +func (c *FoldProofTest[S, G1El, G2El, GTEl]) Define(api frontend.API) error { - f := make([]fr_bls12381.Element, polynomialSize) - for i := range f { - f[i].SetRandom() + verifier, err := NewVerifier[S, G1El, G2El, GTEl](api) + if err != nil { + return fmt.Errorf("get pairing: %w", err) } - com, err := kzg_bls12381.Commit(f, srs.Pk) - assert.NoError(err) + // pick a number on byte shorter than the modulus size + var target big.Int + target.SetUint64(1) + nbBits := api.Compiler().Field().BitLen() + nn := ((nbBits+7)/8)*8 - 8 + target.Lsh(&target, uint(nn)) - var point fr_bls12381.Element - point.SetRandom() - proof, err := kzg_bls12381.Open(f, point, srs.Pk) - assert.NoError(err) + // create the wrapped hash function + whSnark, err := recursion.NewHash(api, &target, true) + if err != nil { + return err + } - if err = kzg_bls12381.Verify(&com, &proof, point, srs.Vk); err != nil { - t.Fatal("verify proof", err) + // op, com, err := verifier.FoldProof(c.Digests[:], c.BatchOpeningProof, c.Point, whSnark) + foldedProof, foldedDigests, err := verifier.FoldProof(c.Digests[:], c.BatchOpeningProof, c.Point, whSnark) + if err != nil { + return err } - wCmt, err := ValueOfCommitment[sw_bls12381.G1Affine](com) - assert.NoError(err) - wProof, err := ValueOfOpeningProof[sw_bls12381.Scalar, sw_bls12381.G1Affine](point, proof) - assert.NoError(err) - wVk, err := ValueOfVerifyingKey[sw_bls12381.G2Affine](srs.Vk) - assert.NoError(err) + verifier.ec.AssertIsEqual(&foldedDigests.G1El, &c.ExpectedFoldedDigest.G1El) + verifier.ec.AssertIsEqual(&foldedProof.Quotient, &c.ExpectedFoldedProof.Quotient) + verifier.scalarApi.AssertIsEqual(&foldedProof.ClaimedValue, &c.ExpectedFoldedProof.ClaimedValue) - assignment := KZGVerificationCircuit[sw_bls12381.Scalar, sw_bls12381.G1Affine, sw_bls12381.G2Affine, sw_bls12381.GTEl]{ - VerifyingKey: wVk, - Commitment: wCmt, - OpeningProof: wProof, - } - assert.CheckCircuit(&KZGVerificationCircuit[sw_bls12381.Scalar, sw_bls12381.G1Affine, sw_bls12381.G2Affine, sw_bls12381.GTEl]{}, test.WithValidAssignment(&assignment)) + return nil } -func TestKZGVerificationEmulated3(t *testing.T) { +func TestFoldProof(t *testing.T) { + assert := test.NewAssert(t) - alpha, err := rand.Int(rand.Reader, ecc.BW6_761.ScalarField()) + // prepare test data + alpha, err := rand.Int(rand.Reader, ecc.BN254.ScalarField()) assert.NoError(err) - srs, err := kzg_bw6761.NewSRS(kzgSize, alpha) + srs, err := kzg_bn254.NewSRS(kzgSize, alpha) assert.NoError(err) - f := make([]fr_bw6761.Element, polynomialSize) - for i := range f { - f[i].SetRandom() + var polynomials [10][]fr_bn254.Element + var coms [10]kzg_bn254.Digest + for i := 0; i < 10; i++ { + polynomials[i] = make([]fr_bn254.Element, polynomialSize) + for j := 0; j < polynomialSize; j++ { + polynomials[i][j].SetRandom() + } + coms[i], err = kzg_bn254.Commit(polynomials[i], srs.Pk) + assert.NoError(err) } - com, err := kzg_bw6761.Commit(f, srs.Pk) + var point fr_bn254.Element + point.SetRandom() + var target big.Int + target.SetUint64(1) + nbBits := ecc.BLS12_381.ScalarField().BitLen() + nn := ((nbBits+7)/8)*8 - 8 + target.Lsh(&target, uint(nn)) + h, err := recursion.NewShort(ecc.BLS12_381.ScalarField(), &target) assert.NoError(err) - var point fr_bw6761.Element - point.SetRandom() - proof, err := kzg_bw6761.Open(f, point, srs.Pk) + batchOpeningProof, err := kzg_bn254.BatchOpenSinglePoint(polynomials[:], coms[:], point, h, srs.Pk) assert.NoError(err) - if err = kzg_bw6761.Verify(&com, &proof, point, srs.Vk); err != nil { - t.Fatal("verify proof", err) - } + foldedProofs, foldedDigest, err := kzg_bn254.FoldProof(coms[:], &batchOpeningProof, point, h) + assert.NoError(err) - wCmt, err := ValueOfCommitment[sw_bw6761.G1Affine](com) + // prepare witness + wPoint, err := ValueOfScalar[emulated.BN254Fr](point) + assert.NoError(err) + var wDigests [10]Commitment[sw_bn254.G1Affine] + for i := 0; i < 10; i++ { + wDigests[i], err = ValueOfCommitment[sw_bn254.G1Affine](coms[i]) + assert.NoError(err) + } + wBatchOpeningProof, err := ValueOfBatchOpeningProof[emulated.BN254Fr, sw_bn254.G1Affine](batchOpeningProof) assert.NoError(err) - wProof, err := ValueOfOpeningProof[sw_bw6761.Scalar, sw_bw6761.G1Affine](point, proof) + wExpectedFoldedProof, err := ValueOfOpeningProof[emulated.BN254Fr, sw_bn254.G1Affine](foldedProofs) assert.NoError(err) - wVk, err := ValueOfVerifyingKey[sw_bw6761.G2Affine](srs.Vk) + wExpectedFoldedDigest, err := ValueOfCommitment[sw_bn254.G1Affine](foldedDigest) assert.NoError(err) - assignment := KZGVerificationCircuit[sw_bw6761.Scalar, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{ - VerifyingKey: wVk, - Commitment: wCmt, - OpeningProof: wProof, + assignment := FoldProofTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ + Point: wPoint, + Digests: wDigests, + BatchOpeningProof: wBatchOpeningProof, + ExpectedFoldedProof: wExpectedFoldedProof, + ExpectedFoldedDigest: wExpectedFoldedDigest, } - assert.CheckCircuit(&KZGVerificationCircuit[sw_bw6761.Scalar, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{}, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BN254)) -} -func TestKZGVerificationTwoChain(t *testing.T) { - assert := test.NewAssert(t) + var circuit FoldProofTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl] + circuit.BatchOpeningProof.ClaimedValues = make([]emulated.Element[emulated.BN254Fr], 10) + assert.CheckCircuit(&circuit, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) - alpha, err := rand.Int(rand.Reader, ecc.BLS12_377.ScalarField()) - assert.NoError(err) - srs, err := kzg_bls12377.NewSRS(kzgSize, alpha) - assert.NoError(err) +} - f := make([]fr_bls12377.Element, polynomialSize) - for i := range f { - f[i].SetRandom() - } +//-------------------------------------------------------- +// Batch verify single point - com, err := kzg_bls12377.Commit(f, srs.Pk) - assert.NoError(err) +type BatchVerifySinglePointTest[S emulated.FieldParams, G1El, G2El, GTEl any] struct { + Vk VerifyingKey[G1El, G2El] + Point emulated.Element[S] + Digests [10]Commitment[G1El] + BatchOpeningProof BatchOpeningProof[S, G1El] +} - var point fr_bls12377.Element - point.SetRandom() - proof, err := kzg_bls12377.Open(f, point, srs.Pk) - assert.NoError(err) +func (c *BatchVerifySinglePointTest[S, G1El, G2El, GTEl]) Define(api frontend.API) error { - if err = kzg_bls12377.Verify(&com, &proof, point, srs.Vk); err != nil { - t.Fatal("verify proof", err) + verifier, err := NewVerifier[S, G1El, G2El, GTEl](api) + if err != nil { + return fmt.Errorf("get pairing: %w", err) } - wCmt, err := ValueOfCommitment[sw_bls12377.G1Affine](com) - assert.NoError(err) - wProof, err := ValueOfOpeningProof[sw_bls12377.Scalar, sw_bls12377.G1Affine](point, proof) - assert.NoError(err) - wVk, err := ValueOfVerifyingKey[sw_bls12377.G2Affine](srs.Vk) - assert.NoError(err) + // pick a number on byte shorter than the modulus size + var target big.Int + target.SetUint64(1) + nbBits := api.Compiler().Field().BitLen() + nn := ((nbBits+7)/8)*8 - 8 + target.Lsh(&target, uint(nn)) - assignment := KZGVerificationCircuit[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ - VerifyingKey: wVk, - Commitment: wCmt, - OpeningProof: wProof, + // create the wrapped hash function + whSnark, err := recursion.NewHash(api, &target, true) + if err != nil { + return err } - assert.CheckCircuit(&KZGVerificationCircuit[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{}, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BW6_761)) + // op, com, err := verifier.FoldProof(c.Digests[:], c.BatchOpeningProof, c.Point, whSnark) + verifier.BatchVerifySinglePoint(c.Digests[:], c.BatchOpeningProof, c.Point, whSnark, c.Vk) + + return nil } -func TestKZGVerificationTwoChain2(t *testing.T) { +func TestBatchVerifySinglePoint(t *testing.T) { + assert := test.NewAssert(t) - alpha, err := rand.Int(rand.Reader, ecc.BLS24_315.ScalarField()) + // prepare test data + alpha, err := rand.Int(rand.Reader, ecc.BN254.ScalarField()) assert.NoError(err) - srs, err := kzg_bls24315.NewSRS(kzgSize, alpha) + srs, err := kzg_bn254.NewSRS(kzgSize, alpha) assert.NoError(err) - f := make([]fr_bls24315.Element, polynomialSize) - for i := range f { - f[i].SetRandom() + var polynomials [10][]fr_bn254.Element + var coms [10]kzg_bn254.Digest + for i := 0; i < 10; i++ { + polynomials[i] = make([]fr_bn254.Element, polynomialSize) + for j := 0; j < polynomialSize; j++ { + polynomials[i][j].SetRandom() + } + coms[i], err = kzg_bn254.Commit(polynomials[i], srs.Pk) + assert.NoError(err) } - com, err := kzg_bls24315.Commit(f, srs.Pk) + // random point at which the polynomials are evaluated + var point fr_bn254.Element + point.SetRandom() + + // build short hash, we pick a number one byte less than the snark field... + var target big.Int + target.SetUint64(1) + nbBits := ecc.BLS12_381.ScalarField().BitLen() + nn := ((nbBits+7)/8)*8 - 8 + target.Lsh(&target, uint(nn)) + h, err := recursion.NewShort(ecc.BLS12_381.ScalarField(), &target) assert.NoError(err) - var point fr_bls24315.Element - point.SetRandom() - proof, err := kzg_bls24315.Open(f, point, srs.Pk) + batchOpeningProof, err := kzg_bn254.BatchOpenSinglePoint(polynomials[:], coms[:], point, h, srs.Pk) assert.NoError(err) - if err = kzg_bls24315.Verify(&com, &proof, point, srs.Vk); err != nil { - t.Fatal("verify proof", err) - } + err = kzg_bn254.BatchVerifySinglePoint(coms[:], &batchOpeningProof, point, h, srs.Vk) + assert.NoError(err) - wCmt, err := ValueOfCommitment[sw_bls24315.G1Affine](com) + // prepare witness + wVk, err := ValueOfVerifyingKey[sw_bn254.G1Affine, sw_bn254.G2Affine](srs.Vk) assert.NoError(err) - wProof, err := ValueOfOpeningProof[sw_bls24315.Scalar, sw_bls24315.G1Affine](point, proof) + wPoint, err := ValueOfScalar[emulated.BN254Fr](point) assert.NoError(err) - wVk, err := ValueOfVerifyingKey[sw_bls24315.G2Affine](srs.Vk) + var wDigests [10]Commitment[sw_bn254.G1Affine] + for i := 0; i < 10; i++ { + wDigests[i], err = ValueOfCommitment[sw_bn254.G1Affine](coms[i]) + assert.NoError(err) + } + wBatchOpeningProof, err := ValueOfBatchOpeningProof[emulated.BN254Fr, sw_bn254.G1Affine](batchOpeningProof) assert.NoError(err) - assignment := KZGVerificationCircuit[sw_bls24315.Scalar, sw_bls24315.G1Affine, sw_bls24315.G2Affine, sw_bls24315.GT]{ - VerifyingKey: wVk, - Commitment: wCmt, - OpeningProof: wProof, + assignment := BatchVerifySinglePointTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ + Vk: wVk, + Point: wPoint, + Digests: wDigests, + BatchOpeningProof: wBatchOpeningProof, } - assert.CheckCircuit(&KZGVerificationCircuit[sw_bls24315.Scalar, sw_bls24315.G1Affine, sw_bls24315.G2Affine, sw_bls24315.GT]{}, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BW6_633)) + var circuit BatchVerifySinglePointTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl] + circuit.BatchOpeningProof.ClaimedValues = make([]emulated.Element[emulated.BN254Fr], 10) + assert.CheckCircuit(&circuit, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) + } -func TestValueOfCommitment(t *testing.T) { - assert := test.NewAssert(t) - assert.Run(func(assert *test.Assert) { - _, _, G1, _ := bn254.Generators() - assignment, err := ValueOfCommitment[sw_bn254.G1Affine](G1) - assert.NoError(err) - _ = assignment - }, "bn254") - assert.Run(func(assert *test.Assert) { - _, _, G1, _ := bls12377.Generators() - assignment, err := ValueOfCommitment[sw_bls12377.G1Affine](G1) - assert.NoError(err) - _ = assignment - }, "bls12377") - assert.Run(func(assert *test.Assert) { - _, _, G1, _ := bls12381.Generators() - assignment, err := ValueOfCommitment[sw_bls12381.G1Affine](G1) - assert.NoError(err) - _ = assignment - }, "bls12381") - assert.Run(func(assert *test.Assert) { - _, _, G1, _ := bw6761.Generators() - assignment, err := ValueOfCommitment[sw_bw6761.G1Affine](G1) - assert.NoError(err) - _ = assignment - }, "bw6761") - assert.Run(func(assert *test.Assert) { - _, _, G1, _ := bls24315.Generators() - assignment, err := ValueOfCommitment[sw_bls24315.G1Affine](G1) - assert.NoError(err) - _ = assignment - }, "bls24315") +//-------------------------------------------------------- +// Batch verify multi point + +// type BatchVerifyMultiPointsTest[S emulated.FieldParams, G1El, G2El, GTEl any] struct { +// Vk VerifyingKey[G1El, G2El] +// Digests [5]Commitment[G1El] +// Proofs [5]OpeningProof[S, G1El] +// Points [5]emulated.Element[S] +// } + +type BatchVerifyMultiPointsTest[S emulated.FieldParams, G1El, G2El, GTEl any] struct { + Vk VerifyingKey[G1El, G2El] + Digests [2]Commitment[G1El] + Proofs [2]OpeningProof[S, G1El] + Points [2]emulated.Element[S] } -func TestValueOfOpeningProof(t *testing.T) { - assert := test.NewAssert(t) - assert.Run(func(assert *test.Assert) { - _, _, G1, _ := bn254.Generators() - var value, point fr_bn254.Element - value.SetRandom() - point.SetRandom() - proof := kzg_bn254.OpeningProof{ - H: G1, - ClaimedValue: value, - } - assignment, err := ValueOfOpeningProof[sw_bn254.Scalar, sw_bn254.G1Affine](point, proof) - assert.NoError(err) - _ = assignment - }, "bn254") - assert.Run(func(assert *test.Assert) { - _, _, G1, _ := bls12377.Generators() - var value, point fr_bls12377.Element - value.SetRandom() - point.SetRandom() - proof := kzg_bls12377.OpeningProof{ - H: G1, - ClaimedValue: value, - } - assignment, err := ValueOfOpeningProof[sw_bls12377.Scalar, sw_bls12377.G1Affine](point, proof) - assert.NoError(err) - _ = assignment - }, "bls12377") - assert.Run(func(assert *test.Assert) { - _, _, G1, _ := bls12381.Generators() - var value, point fr_bls12381.Element - value.SetRandom() - point.SetRandom() - proof := kzg_bls12381.OpeningProof{ - H: G1, - ClaimedValue: value, - } - assignment, err := ValueOfOpeningProof[sw_bls12381.Scalar, sw_bls12381.G1Affine](point, proof) - assert.NoError(err) - _ = assignment - }, "bls12381") - assert.Run(func(assert *test.Assert) { - _, _, G1, _ := bw6761.Generators() - var value, point fr_bw6761.Element - value.SetRandom() - point.SetRandom() - proof := kzg_bw6761.OpeningProof{ - H: G1, - ClaimedValue: value, - } - assignment, err := ValueOfOpeningProof[sw_bw6761.Scalar, sw_bw6761.G1Affine](point, proof) - assert.NoError(err) - _ = assignment - }, "bw6761") - assert.Run(func(assert *test.Assert) { - _, _, G1, _ := bls24315.Generators() - var value, point fr_bls24315.Element - value.SetRandom() - point.SetRandom() - proof := kzg_bls24315.OpeningProof{ - H: G1, - ClaimedValue: value, - } - assignment, err := ValueOfOpeningProof[sw_bls24315.Scalar, sw_bls24315.G1Affine](point, proof) - assert.NoError(err) - _ = assignment - }, "bls24315") +func (circuit *BatchVerifyMultiPointsTest[S, G1El, G2El, GTEl]) Define(api frontend.API) error { + + verifier, err := NewVerifier[S, G1El, G2El, GTEl](api) + if err != nil { + return fmt.Errorf("get pairing: %w", err) + } + + verifier.BatchVerifyMultiPoints(circuit.Digests[:], circuit.Proofs[:], circuit.Points[:], circuit.Vk) + + return nil } -func TestValueOfSRS(t *testing.T) { +func TestBatchVerifyMultiPoints(t *testing.T) { + assert := test.NewAssert(t) - assert.Run(func(assert *test.Assert) { - _, _, _, G2 := bn254.Generators() - vk := kzg_bn254.VerifyingKey{ - G2: [2]bn254.G2Affine{G2, G2}, + + // prepare test data + alpha, err := rand.Int(rand.Reader, ecc.BN254.ScalarField()) + assert.NoError(err) + srs, err := kzg_bn254.NewSRS(kzgSize, alpha) + assert.NoError(err) + + var polynomials [2][]fr_bn254.Element + var coms [2]kzg_bn254.Digest + for i := 0; i < 2; i++ { + polynomials[i] = make([]fr_bn254.Element, polynomialSize) + for j := 0; j < polynomialSize; j++ { + polynomials[i][j].SetRandom() } - assignment, err := ValueOfVerifyingKey[sw_bn254.G2Affine](vk) + coms[i], err = kzg_bn254.Commit(polynomials[i], srs.Pk) assert.NoError(err) - _ = assignment - }, "bn254") - assert.Run(func(assert *test.Assert) { - _, _, _, G2 := bls12377.Generators() - vk := kzg_bls12377.VerifyingKey{ - G2: [2]bls12377.G2Affine{G2, G2}, - } - assignment, err := ValueOfVerifyingKey[sw_bls12377.G2Affine](vk) + } + + // random points at which the polynomials are evaluated + var points [2]fr_bn254.Element + for i := 0; i < 2; i++ { + points[i].SetRandom() + } + + // build opening proofs + var openingProofs [2]kzg_bn254.OpeningProof + for i := 0; i < 2; i++ { + openingProofs[i], err = kzg_bn254.Open(polynomials[i], points[i], srs.Pk) assert.NoError(err) - _ = assignment - }, "bls12377") - assert.Run(func(assert *test.Assert) { - _, _, _, G2 := bls12381.Generators() - vk := kzg_bls12381.VerifyingKey{ - G2: [2]bls12381.G2Affine{G2, G2}, - } - assignment, err := ValueOfVerifyingKey[sw_bls12381.G2Affine](vk) + } + + // check that the proofs are correct + err = kzg_bn254.BatchVerifyMultiPoints(coms[:], openingProofs[:], points[:], srs.Vk) + assert.NoError(err) + + // prepare witness + wVk, err := ValueOfVerifyingKey[sw_bn254.G1Affine, sw_bn254.G2Affine](srs.Vk) + assert.NoError(err) + var wDigests [2]Commitment[sw_bn254.G1Affine] + var wPoints [2]emulated.Element[emulated.BN254Fr] + var wOpeningProofs [2]OpeningProof[emulated.BN254Fr, sw_bn254.G1Affine] + for i := 0; i < 2; i++ { + wPoints[i], err = ValueOfScalar[emulated.BN254Fr](points[i]) assert.NoError(err) - _ = assignment - }, "bls12381") - assert.Run(func(assert *test.Assert) { - _, _, _, G2 := bw6761.Generators() - vk := kzg_bw6761.VerifyingKey{ - G2: [2]bw6761.G2Affine{G2, G2}, - } - assignment, err := ValueOfVerifyingKey[sw_bw6761.G2Affine](vk) + wDigests[i], err = ValueOfCommitment[sw_bn254.G1Affine](coms[i]) assert.NoError(err) - _ = assignment - }, "bw6761") - assert.Run(func(assert *test.Assert) { - _, _, _, G2 := bls24315.Generators() - vk := kzg_bls24315.VerifyingKey{ - G2: [2]bls24315.G2Affine{G2, G2}, - } - assignment, err := ValueOfVerifyingKey[sw_bls24315.G2Affine](vk) + wOpeningProofs[i], err = ValueOfOpeningProof[emulated.BN254Fr, sw_bn254.G1Affine](openingProofs[i]) assert.NoError(err) - _ = assignment - }, "bls24315") + } + + assignment := BatchVerifyMultiPointsTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ + Vk: wVk, + Points: wPoints, + Digests: wDigests, + Proofs: wOpeningProofs, + } + + var circuit BatchVerifyMultiPointsTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl] + assert.CheckCircuit(&circuit, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) + } + +//-------------------------------------------------------- +// derive gamma + +// type DeriveGammaTest[S emulated.FieldParams, G1El, G2El, GTEl any] struct { +// Point emulated.Element[S] +// Digests [10]Commitment[G1El] +// ClaimedValues [10]emulated.Element[S] +// Gamma emulated.Element[S] +// } + +// func (circuit *DeriveGammaTest[S, G1El, G2El, GTEl]) Define(api frontend.API) error { + +// verifier, err := NewVerifier[S, G1El, G2El, GTEl](api) +// if err != nil { +// return fmt.Errorf("get pairing: %w", err) +// } + +// // pick a number on byte shorter than the modulus size +// var target big.Int +// target.SetUint64(1) +// nbBits := api.Compiler().Field().BitLen() +// nn := ((nbBits+7)/8)*8 - 8 +// target.Lsh(&target, uint(nn)) + +// // create the wrapped hash function +// whSnark, err := recursion.NewHash(api, &target, true) +// if err != nil { +// return err +// } + +// res, err := verifier.deriveGamma(circuit.Point, circuit.Digests[:], circuit.ClaimedValues[:], whSnark) +// if err != nil { +// return err +// } +// verifier.scalarApi.AssertIsEqual(&res, &circuit.Gamma) +// return nil +// } + +// func TestDeriveGamma(t *testing.T) { + +// assert := test.NewAssert(t) + +// // prepare test data +// alpha, err := rand.Int(rand.Reader, ecc.BN254.ScalarField()) +// assert.NoError(err) +// srs, err := kzg_bn254.NewSRS(kzgSize, alpha) +// assert.NoError(err) + +// var polynomials [10][]fr_bn254.Element +// var digests [10]kzg_bn254.Digest +// for i := 0; i < 10; i++ { +// polynomials[i] = make([]fr_bn254.Element, polynomialSize) +// for j := 0; j < polynomialSize; j++ { +// polynomials[i][j].SetRandom() +// } +// digests[i], err = kzg_bn254.Commit(polynomials[i], srs.Pk) +// assert.NoError(err) +// } + +// var point fr_bn254.Element +// point.SetRandom() +// var target big.Int +// target.SetUint64(1) +// nbBits := ecc.BLS12_381.ScalarField().BitLen() +// nn := ((nbBits+7)/8)*8 - 8 +// target.Lsh(&target, uint(nn)) +// h, err := recursion.NewShort(ecc.BLS12_381.ScalarField(), &target) +// assert.NoError(err) + +// batchOpeningProof, err := kzg_bn254.BatchOpenSinglePoint(polynomials[:], digests[:], point, h, srs.Pk) +// assert.NoError(err) + +// gamma, err := kzg_bn254.DeriveGamma(point, digests[:], batchOpeningProof.ClaimedValues, h) +// assert.NoError(err) + +// // prepare witness +// wPoint, err := ValueOfScalar[emulated.BN254Fr](point) +// assert.NoError(err) +// var wDigests [10]Commitment[sw_bn254.G1Affine] +// for i := 0; i < 10; i++ { +// wDigests[i], err = ValueOfCommitment[sw_bn254.G1Affine](digests[i]) +// assert.NoError(err) +// } +// var wClaimedValues [10]emulated.Element[emulated.BN254Fr] +// for i := 0; i < 10; i++ { +// wClaimedValues[i], err = ValueOfScalar[emulated.BN254Fr](batchOpeningProof.ClaimedValues[i]) +// assert.NoError(err) +// } +// wGmma, err := ValueOfScalar[emulated.BN254Fr](gamma) +// assert.NoError(err) + +// assignment := DeriveGammaTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ +// Point: wPoint, +// Digests: wDigests, +// ClaimedValues: wClaimedValues, +// Gamma: wGmma, +// } + +// assert.CheckCircuit(&DeriveGammaTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{}, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) +// } diff --git a/std/commitments/kzg_refactor/verifier.go b/std/commitments/kzg_refactor/verifier.go deleted file mode 100644 index 1d6200e02f..0000000000 --- a/std/commitments/kzg_refactor/verifier.go +++ /dev/null @@ -1,337 +0,0 @@ -package kzg_refactor - -import ( - "errors" - "fmt" - - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra" - fiatshamir "github.com/consensys/gnark/std/fiat-shamir" - "github.com/consensys/gnark/std/hash" - "github.com/consensys/gnark/std/math/emulated" -) - -var ( - ErrInvalidNbDigests = errors.New("number of digests is not the same as the number of polynomials") - ErrZeroNbDigests = errors.New("number of digests is zero") -) - -// Commitment is an KZG commitment to a polynomial. Use [ValueOfCommitment] to -// initialize a witness from the native commitment. -type Commitment[G1El any] struct { - G1El G1El -} - -// OpeningProof embeds the opening proof that polynomial evaluated at Point is -// equal to ClaimedValue. Use [ValueOfOpeningProof] to initialize a witness from -// a native opening proof. -type OpeningProof[S emulated.FieldParams, G1El any] struct { - Quotient G1El - ClaimedValue emulated.Element[S] -} - -// VerifyingKey is the trusted setup for KZG polynomial commitment scheme. Use -// [ValueOfVerifyingKey] to initialize a witness from the native VerifyingKey. -type VerifyingKey[G1El, G2El any] struct { - G2 [2]G2El - G1 G1El -} - -type BatchOpeningProof[S emulated.FieldParams, G1El any] struct { - Quotient G1El - ClaimedValues []emulated.Element[S] -} - -// B base field, S scalar -// S here is emulated.Element[S] -type IVerifier[S emulated.FieldParams, G1El, G2El any] interface { - CheckOpeningProof(Commitment[G1El], OpeningProof[S, G1El], emulated.Element[S], VerifyingKey[G1El, G2El]) error - FoldProof([]Commitment[G1El], BatchOpeningProof[S, G1El], emulated.Element[S], hash.FieldHasher, ...frontend.Variable) (OpeningProof[S, G1El], Commitment[G1El], error) - BatchVerifySinglePoint([]Commitment[G1El], BatchOpeningProof[S, G1El], emulated.Element[S], VerifyingKey[G1El, G2El], hash.FieldHasher, ...frontend.Variable) error - BatchVerifyMultiPoints([]Commitment[G1El], []OpeningProof[S, G1El], []emulated.Element[S], VerifyingKey[G1El, G2El]) error -} - -type Verifier[S emulated.FieldParams, G1El, G2El, GtEl any] struct { - api frontend.API - scalarApi *emulated.Field[S] - ec algebra.Curve[emulated.Element[S], G1El] - pairing algebra.Pairing[G1El, G2El, GtEl] -} - -func NewVerifier[S emulated.FieldParams, G1El, G2El, GtEl any](api frontend.API) (Verifier[S, G1El, G2El, GtEl], error) { - var res Verifier[S, G1El, G2El, GtEl] - var err error - res.api = api - res.ec, err = algebra.GetCurve[emulated.Element[S], G1El](api) - if err != nil { - return res, err - } - res.scalarApi, err = emulated.NewField[S](api) - if err != nil { - return res, err - } - res.pairing, err = algebra.GetPairing[G1El, G2El, GtEl](api) - if err != nil { - return res, err - } - - return res, nil -} - -// S here is emulated.FieldParams -func (v *Verifier[S, G1El, G2El, GTEl]) CheckOpeningProof(digest Commitment[G1El], proof OpeningProof[S, G1El], point emulated.Element[S], vk VerifyingKey[G1El, G2El]) error { - - claimedValueG1 := v.ec.ScalarMulBase(&proof.ClaimedValue) - - // [f(α) - f(a)]G₁ - fminusfaG1 := v.ec.Neg(claimedValueG1) - fminusfaG1 = v.ec.Add(fminusfaG1, &digest.G1El) - - // [-H(α)]G₁ - negQuotientPoly := v.ec.Neg(&proof.Quotient) - - // [f(α) - f(a) + a*H(α)]G₁ - totalG1 := v.ec.ScalarMul(&proof.Quotient, &point) - totalG1 = v.ec.Add(totalG1, fminusfaG1) - - // e([f(α)-f(a)+aH(α)]G₁], G₂).e([-H(α)]G₁, [α]G₂) == 1 - if err := v.pairing.PairingCheck( - []*G1El{totalG1, negQuotientPoly}, - []*G2El{&vk.G2[0], &vk.G2[1]}, - ); err != nil { - return fmt.Errorf("pairing check: %w", err) - } - return nil - -} - -func (v *Verifier[S, G1El, G2El, GTEl]) FoldProof(digests []Commitment[G1El], batchOpeningProof BatchOpeningProof[S, G1El], point emulated.Element[S], hf hash.FieldHasher, dataTranscript ...frontend.Variable) (OpeningProof[S, G1El], Commitment[G1El], error) { - - nbDigests := len(digests) - - // check consistency between numbers of claims vs number of digests - if nbDigests != len(batchOpeningProof.ClaimedValues) { - return OpeningProof[S, G1El]{}, Commitment[G1El]{}, ErrInvalidNbDigests - } - - // derive the challenge γ, binded to the point and the commitments - gamma, err := v.deriveGamma(point, digests, batchOpeningProof.ClaimedValues, hf, dataTranscript...) - if err != nil { - return OpeningProof[S, G1El]{}, Commitment[G1El]{}, err - } - - // fold the claimed values and digests - // gammai = [1,γ,γ²,..,γⁿ⁻¹] - gammai := make([]emulated.Element[S], nbDigests) - gammai[0] = emulated.ValueOf[S](1) - if nbDigests > 1 { - gammai[1] = gamma - } - for i := 2; i < nbDigests; i++ { - gammai[i] = *(v.scalarApi.Mul(&gammai[i-1], &gamma)) - } - - foldedDigests, foldedEvaluations := v.fold(digests, batchOpeningProof.ClaimedValues, gammai) - - var foldedProof OpeningProof[S, G1El] - foldedProof.Quotient = batchOpeningProof.Quotient - foldedProof.ClaimedValue = foldedEvaluations - return foldedProof, foldedDigests, nil - - // create the folded opening proof - // var res OpeningProof[S, G1El] - // res.ClaimedValue = batchOpeningProof.ClaimedValues[0] - // res.Quotient = batchOpeningProof.Quotient - // return res, digests[0], nil - -} - -func (v *Verifier[S, G1El, G2El, GTEl]) BatchVerifySinglePoint(digests []Commitment[G1El], batchOpeningProof BatchOpeningProof[S, G1El], point emulated.Element[S], hf hash.FieldHasher, vk VerifyingKey[G1El, G2El], dataTranscript ...frontend.Variable) error { - - // fold the proof - foldedProof, foldedDigest, err := v.FoldProof(digests, batchOpeningProof, point, hf, dataTranscript...) - if err != nil { - return err - } - - // verify the foldedProof against the foldedDigest - err = v.CheckOpeningProof(foldedDigest, foldedProof, point, vk) - - return err -} - -func (v *Verifier[S, G1El, G2El, GTEl]) BatchVerifyMultiPoints(digests []Commitment[G1El], proofs []OpeningProof[S, G1El], points []emulated.Element[S], vk VerifyingKey[G1El, G2El]) error { - - // check consistency nb proogs vs nb digests - if len(digests) != len(proofs) || len(digests) != len(points) { - return ErrInvalidNbDigests - } - - // len(digests) should be nonzero because of randomNumbers - if len(digests) == 0 { - return ErrZeroNbDigests - } - - // if only one digest, call Verify - if len(digests) == 1 { - return v.CheckOpeningProof(digests[0], proofs[0], points[0], vk) - } - - // sample random numbers λᵢ for sampling - randomNumbers := make([]emulated.Element[S], len(digests)) - randomNumbers[0] = emulated.ValueOf[S](1) - for i := 1; i < len(randomNumbers); i++ { - // TODO use real random numbers, follow the solidity smart contract to know which variables are used as seed - randomNumbers[i] = emulated.ValueOf[S](42) - } - - // fold the committed quotients compute ∑ᵢλᵢ[Hᵢ(α)]G₁ - var foldedQuotients G1El - quotients := make([]G1El, len(proofs)) - for i := 0; i < len(randomNumbers); i++ { - quotients[i] = proofs[i].Quotient - } - foldedQuotients = *v.ec.ScalarMul("ients[0], &randomNumbers[0]) - for i := 1; i < len(digests); i++ { - tmp := *v.ec.ScalarMul("ients[i], &randomNumbers[i]) - foldedQuotients = *v.ec.Add(&tmp, &foldedQuotients) - } - // aa := v.ec.MarshalG1(foldedQuotients) - // slices.Reverse(aa[:256]) - // slices.Reverse(aa[256:]) - // xx := v.api.FromBinary(aa[:256]...) - // yy := v.api.FromBinary(aa[256:]...) - // v.api.Println(xx) - // v.api.Println(yy) - - // fold digests and evals - evals := make([]emulated.Element[S], len(digests)) - - // fold the digests: ∑ᵢλᵢ[f_i(α)]G₁ - // fold the evals : ∑ᵢλᵢfᵢ(aᵢ) - for i := 0; i < len(digests); i++ { - - evals[i] = proofs[i].ClaimedValue - - // aa := v.scalarApi.ToBits(&proofs[i].ClaimedValue) - // bb := v.api.FromBinary(aa...) - // v.api.Println(bb) - } - foldedDigests, foldedEvals := v.fold(digests, evals, randomNumbers) - - // bb := v.scalarApi.ToBits(&foldedEvals) - // bbb := v.api.FromBinary(bb...) - // v.api.Println(bbb) - - // aa := v.ec.MarshalG1(foldedDigests.G1El) - // slices.Reverse(aa[:256]) - // slices.Reverse(aa[256:]) - // xx := v.api.FromBinary(aa[:256]...) - // yy := v.api.FromBinary(aa[256:]...) - // v.api.Println(xx) - // v.api.Println(yy) - - // compute commitment to folded Eval [∑ᵢλᵢfᵢ(aᵢ)]G₁ - foldedEvalsCommit := v.ec.ScalarMul(&vk.G1, &foldedEvals) - - // bb := v.scalarApi.ToBits(&foldedEvals) - // bbb := v.api.FromBinary(bb...) - // v.api.Println(bbb) - - // compute foldedDigests = ∑ᵢλᵢ[fᵢ(α)]G₁ - [∑ᵢλᵢfᵢ(aᵢ)]G₁ - // foldedDigests.Sub(&foldedDigests, &foldedEvalsCommit) - tmp := v.ec.Neg(foldedEvalsCommit) - foldedDigests.G1El = *v.ec.Add(&foldedDigests.G1El, tmp) - - // combien the points and the quotients using γᵢ - // ∑ᵢλᵢ[p_i]([Hᵢ(α)]G₁) - var foldedPointsQuotients G1El - for i := 0; i < len(randomNumbers); i++ { - randomNumbers[i] = *v.scalarApi.Mul(&randomNumbers[i], &points[i]) - // randomNumbers[i] = *v.scalarApi.Reduce(&randomNumbers[i]) - } - foldedPointsQuotients = *v.ec.ScalarMul("ients[0], &randomNumbers[0]) - for i := 1; i < len(digests); i++ { - tmp = v.ec.ScalarMul("ients[i], &randomNumbers[i]) - foldedPointsQuotients = *v.ec.Add(&foldedPointsQuotients, tmp) - } - - // ∑ᵢλᵢ[f_i(α)]G₁ - [∑ᵢλᵢfᵢ(aᵢ)]G₁ + ∑ᵢλᵢ[p_i]([Hᵢ(α)]G₁) - // = [∑ᵢλᵢf_i(α) - ∑ᵢλᵢfᵢ(aᵢ) + ∑ᵢλᵢpᵢHᵢ(α)]G₁ - foldedDigests.G1El = *v.ec.Add(&foldedDigests.G1El, &foldedPointsQuotients) - - // -∑ᵢλᵢ[Qᵢ(α)]G₁ - // foldedQuotients.Neg(&foldedQuotients) - foldedQuotients = *v.ec.Neg(&foldedQuotients) - - // pairing check - err := v.pairing.PairingCheck( - []*G1El{&foldedDigests.G1El, &foldedQuotients}, - []*G2El{&vk.G2[0], &vk.G2[1]}, - ) - - return err -} - -func (v *Verifier[S, G1El, G2El, GTEl]) fold(digests []Commitment[G1El], fai, ci []emulated.Element[S]) (Commitment[G1El], emulated.Element[S]) { - - // length inconsistency between digests and evaluations should have been done before calling this function - nbDigests := len(digests) - - // fold the claimed values ∑ᵢcᵢf(aᵢ) - var foldedEvaluations, tmp emulated.Element[S] - foldedEvaluations = emulated.ValueOf[S](0) - for i := 0; i < nbDigests; i++ { - tmp = *v.scalarApi.Mul(&fai[i], &ci[i]) - foldedEvaluations = *v.scalarApi.Add(&foldedEvaluations, &tmp) - } - - // fold the digests ∑ᵢ[cᵢ]([fᵢ(α)]G₁) - var foldedDigests Commitment[G1El] - foldedDigests.G1El = *v.ec.ScalarMul(&digests[0].G1El, &ci[0]) - for i := 1; i < nbDigests; i++ { - tmp := *v.ec.ScalarMul(&digests[i].G1El, &ci[i]) - foldedDigests.G1El = *v.ec.Add(&tmp, &foldedDigests.G1El) - } - - // folding done - return foldedDigests, foldedEvaluations - -} - -// deriveGamma derives a challenge using Fiat Shamir to fold proofs. -// dataTranscript are supposed to be bits. -// /!\ bitMode = true here /!\ -func (v *Verifier[S, G1El, G2El, GTEl]) deriveGamma(point emulated.Element[S], digests []Commitment[G1El], claimedValues []emulated.Element[S], hf hash.FieldHasher, dataTranscript ...frontend.Variable) (emulated.Element[S], error) { - - // derive the challenge gamma, binded to the point and the commitments - fs := fiatshamir.NewTranscript(v.api, hf, "gamma") - - marhsalledPoint := v.ec.MarshalScalar(point) - if err := fs.Bind("gamma", marhsalledPoint); err != nil { - return emulated.Element[S]{}, err - } - for i := range digests { - if err := fs.Bind("gamma", v.ec.MarshalG1(digests[i].G1El)); err != nil { - return emulated.Element[S]{}, err - } - } - for i := range claimedValues { - if err := fs.Bind("gamma", v.ec.MarshalScalar(claimedValues[i])); err != nil { - return emulated.Element[S]{}, err - } - } - - if err := fs.Bind("gamma", dataTranscript); err != nil { - return emulated.Element[S]{}, err - } - - gamma, err := fs.ComputeChallenge("gamma", true) - if err != nil { - return emulated.Element[S]{}, err - } - bGamma := v.api.ToBinary(gamma) - gammaS := v.scalarApi.FromBits(bGamma...) - - return *gammaS, nil -} diff --git a/std/commitments/kzg_refactor/verifier_test.go b/std/commitments/kzg_refactor/verifier_test.go deleted file mode 100644 index e8dba0615a..0000000000 --- a/std/commitments/kzg_refactor/verifier_test.go +++ /dev/null @@ -1,560 +0,0 @@ -package kzg_refactor - -import ( - "crypto/rand" - "fmt" - "math/big" - "testing" - - "github.com/consensys/gnark-crypto/ecc" - fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" - kzg_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/kzg" - "github.com/consensys/gnark/backend" - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra/emulated/sw_bn254" - "github.com/consensys/gnark/std/math/emulated" - "github.com/consensys/gnark/std/recursion" - "github.com/consensys/gnark/test" -) - -const ( - kzgSize = 128 - polynomialSize = 100 -) - -//-------------------------------------------------------- -// Single opening single point - -type KZGVerificationCircuit[S emulated.FieldParams, G1El, G2El, GTEl any] struct { - Vk VerifyingKey[G1El, G2El] - Digest Commitment[G1El] - Proof OpeningProof[S, G1El] - Point emulated.Element[S] -} - -func (c *KZGVerificationCircuit[S, G1El, G2El, GTEl]) Define(api frontend.API) error { - verifier, err := NewVerifier[S, G1El, G2El, GTEl](api) - if err != nil { - return fmt.Errorf("get pairing: %w", err) - } - if err := verifier.CheckOpeningProof(c.Digest, c.Proof, c.Point, c.Vk); err != nil { - return fmt.Errorf("assert proof: %w", err) - } - return nil -} - -func TestKZGVerificationEmulated(t *testing.T) { - - assert := test.NewAssert(t) - - alpha, err := rand.Int(rand.Reader, ecc.BN254.ScalarField()) - assert.NoError(err) - srs, err := kzg_bn254.NewSRS(kzgSize, alpha) - assert.NoError(err) - - f := make([]fr_bn254.Element, polynomialSize) - for i := range f { - f[i].SetRandom() - } - - com, err := kzg_bn254.Commit(f, srs.Pk) - assert.NoError(err) - - var point fr_bn254.Element - point.SetRandom() - proof, err := kzg_bn254.Open(f, point, srs.Pk) - assert.NoError(err) - - if err = kzg_bn254.Verify(&com, &proof, point, srs.Vk); err != nil { - t.Fatal("verify proof", err) - } - - wCmt, err := ValueOfCommitment[sw_bn254.G1Affine](com) - assert.NoError(err) - wProof, err := ValueOfOpeningProof[emulated.BN254Fr, sw_bn254.G1Affine](proof) - assert.NoError(err) - wVk, err := ValueOfVerifyingKey[sw_bn254.G1Affine, sw_bn254.G2Affine](srs.Vk) - assert.NoError(err) - - // wPoint, err := ValueOfScalar[emulated.BN254Fr](point) - wPoint, err := ValueOfScalar[emulated.BN254Fr](point) - assert.NoError(err) - - assignment := KZGVerificationCircuit[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ - Vk: wVk, - Digest: wCmt, - Proof: wProof, - Point: wPoint, - } - assert.CheckCircuit(&KZGVerificationCircuit[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{}, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) -} - -//-------------------------------------------------------- -// Slice proof - -// type SliceTest[S emulated.FieldParams, G1El any] struct { -// Proof BatchOpeningProof[S, G1El] -// } - -// func (circuit *SliceTest[S, G1El]) Define(api frontend.API) error { - -// fmt.Println(len(circuit.Proof.ClaimedValues)) -// return nil -// } - -// func TestSlices(t *testing.T) { - -// assert := test.NewAssert(t) - -// // prepare test data -// alpha, err := rand.Int(rand.Reader, ecc.BN254.ScalarField()) -// assert.NoError(err) -// srs, err := kzg_bn254.NewSRS(kzgSize, alpha) -// assert.NoError(err) - -// var polynomials [10][]fr_bn254.Element -// var coms [10]kzg_bn254.Digest -// for i := 0; i < 10; i++ { -// polynomials[i] = make([]fr_bn254.Element, polynomialSize) -// for j := 0; j < polynomialSize; j++ { -// polynomials[i][j].SetRandom() -// } -// coms[i], err = kzg_bn254.Commit(polynomials[i], srs.Pk) -// assert.NoError(err) -// } - -// var point fr_bn254.Element -// point.SetRandom() -// var target big.Int -// target.SetUint64(1) -// nbBits := ecc.BLS12_381.ScalarField().BitLen() -// nn := ((nbBits+7)/8)*8 - 8 -// target.Lsh(&target, uint(nn)) -// h, err := recursion.NewShort(ecc.BLS12_381.ScalarField(), &target) -// assert.NoError(err) - -// batchOpeningProof, err := kzg_bn254.BatchOpenSinglePoint(polynomials[:], coms[:], point, h, srs.Pk) -// assert.NoError(err) - -// _, _, err = kzg_bn254.FoldProof(coms[:], &batchOpeningProof, point, h) -// assert.NoError(err) - -// // circuit -// var circuit SliceTest[emulated.BN254Fr, sw_bn254.G1Affine] -// circuit.Proof.ClaimedValues = make([]emulated.Element[emulated.BN254Fr], 10) - -// var assignment SliceTest[emulated.BN254Fr, sw_bn254.G1Affine] -// // assignment.Proof.ClaimedValues = make([]emulated.Element[emulated.BN254Fr], 10) -// assignment.Proof, err = ValueOfBatchOpeningProof[emulated.BN254Fr, sw_bn254.G1Affine](batchOpeningProof) -// assert.NoError(err) - -// assert.CheckCircuit(&circuit, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) - -// } - -//-------------------------------------------------------- -// Fold proof - -type FoldProofTest[S emulated.FieldParams, G1El, G2El, GTEl any] struct { - Point emulated.Element[S] - Digests [10]Commitment[G1El] - BatchOpeningProof BatchOpeningProof[S, G1El] - ExpectedFoldedProof OpeningProof[S, G1El] - ExpectedFoldedDigest Commitment[G1El] -} - -func (c *FoldProofTest[S, G1El, G2El, GTEl]) Define(api frontend.API) error { - - verifier, err := NewVerifier[S, G1El, G2El, GTEl](api) - if err != nil { - return fmt.Errorf("get pairing: %w", err) - } - - // pick a number on byte shorter than the modulus size - var target big.Int - target.SetUint64(1) - nbBits := api.Compiler().Field().BitLen() - nn := ((nbBits+7)/8)*8 - 8 - target.Lsh(&target, uint(nn)) - - // create the wrapped hash function - whSnark, err := recursion.NewHash(api, &target, true) - if err != nil { - return err - } - - // op, com, err := verifier.FoldProof(c.Digests[:], c.BatchOpeningProof, c.Point, whSnark) - foldedProof, foldedDigests, err := verifier.FoldProof(c.Digests[:], c.BatchOpeningProof, c.Point, whSnark) - if err != nil { - return err - } - - verifier.ec.AssertIsEqual(&foldedDigests.G1El, &c.ExpectedFoldedDigest.G1El) - verifier.ec.AssertIsEqual(&foldedProof.Quotient, &c.ExpectedFoldedProof.Quotient) - verifier.scalarApi.AssertIsEqual(&foldedProof.ClaimedValue, &c.ExpectedFoldedProof.ClaimedValue) - - return nil -} - -func TestFoldProof(t *testing.T) { - - assert := test.NewAssert(t) - - // prepare test data - alpha, err := rand.Int(rand.Reader, ecc.BN254.ScalarField()) - assert.NoError(err) - srs, err := kzg_bn254.NewSRS(kzgSize, alpha) - assert.NoError(err) - - var polynomials [10][]fr_bn254.Element - var coms [10]kzg_bn254.Digest - for i := 0; i < 10; i++ { - polynomials[i] = make([]fr_bn254.Element, polynomialSize) - for j := 0; j < polynomialSize; j++ { - polynomials[i][j].SetRandom() - } - coms[i], err = kzg_bn254.Commit(polynomials[i], srs.Pk) - assert.NoError(err) - } - - var point fr_bn254.Element - point.SetRandom() - var target big.Int - target.SetUint64(1) - nbBits := ecc.BLS12_381.ScalarField().BitLen() - nn := ((nbBits+7)/8)*8 - 8 - target.Lsh(&target, uint(nn)) - h, err := recursion.NewShort(ecc.BLS12_381.ScalarField(), &target) - assert.NoError(err) - - batchOpeningProof, err := kzg_bn254.BatchOpenSinglePoint(polynomials[:], coms[:], point, h, srs.Pk) - assert.NoError(err) - - foldedProofs, foldedDigest, err := kzg_bn254.FoldProof(coms[:], &batchOpeningProof, point, h) - assert.NoError(err) - - // prepare witness - wPoint, err := ValueOfScalar[emulated.BN254Fr](point) - assert.NoError(err) - var wDigests [10]Commitment[sw_bn254.G1Affine] - for i := 0; i < 10; i++ { - wDigests[i], err = ValueOfCommitment[sw_bn254.G1Affine](coms[i]) - assert.NoError(err) - } - wBatchOpeningProof, err := ValueOfBatchOpeningProof[emulated.BN254Fr, sw_bn254.G1Affine](batchOpeningProof) - assert.NoError(err) - wExpectedFoldedProof, err := ValueOfOpeningProof[emulated.BN254Fr, sw_bn254.G1Affine](foldedProofs) - assert.NoError(err) - wExpectedFoldedDigest, err := ValueOfCommitment[sw_bn254.G1Affine](foldedDigest) - assert.NoError(err) - - assignment := FoldProofTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ - Point: wPoint, - Digests: wDigests, - BatchOpeningProof: wBatchOpeningProof, - ExpectedFoldedProof: wExpectedFoldedProof, - ExpectedFoldedDigest: wExpectedFoldedDigest, - } - - var circuit FoldProofTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl] - circuit.BatchOpeningProof.ClaimedValues = make([]emulated.Element[emulated.BN254Fr], 10) - assert.CheckCircuit(&circuit, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) - -} - -//-------------------------------------------------------- -// Batch verify single point - -type BatchVerifySinglePointTest[S emulated.FieldParams, G1El, G2El, GTEl any] struct { - Vk VerifyingKey[G1El, G2El] - Point emulated.Element[S] - Digests [10]Commitment[G1El] - BatchOpeningProof BatchOpeningProof[S, G1El] -} - -func (c *BatchVerifySinglePointTest[S, G1El, G2El, GTEl]) Define(api frontend.API) error { - - verifier, err := NewVerifier[S, G1El, G2El, GTEl](api) - if err != nil { - return fmt.Errorf("get pairing: %w", err) - } - - // pick a number on byte shorter than the modulus size - var target big.Int - target.SetUint64(1) - nbBits := api.Compiler().Field().BitLen() - nn := ((nbBits+7)/8)*8 - 8 - target.Lsh(&target, uint(nn)) - - // create the wrapped hash function - whSnark, err := recursion.NewHash(api, &target, true) - if err != nil { - return err - } - - // op, com, err := verifier.FoldProof(c.Digests[:], c.BatchOpeningProof, c.Point, whSnark) - verifier.BatchVerifySinglePoint(c.Digests[:], c.BatchOpeningProof, c.Point, whSnark, c.Vk) - - return nil -} - -func TestBatchVerifySinglePoint(t *testing.T) { - - assert := test.NewAssert(t) - - // prepare test data - alpha, err := rand.Int(rand.Reader, ecc.BN254.ScalarField()) - assert.NoError(err) - srs, err := kzg_bn254.NewSRS(kzgSize, alpha) - assert.NoError(err) - - var polynomials [10][]fr_bn254.Element - var coms [10]kzg_bn254.Digest - for i := 0; i < 10; i++ { - polynomials[i] = make([]fr_bn254.Element, polynomialSize) - for j := 0; j < polynomialSize; j++ { - polynomials[i][j].SetRandom() - } - coms[i], err = kzg_bn254.Commit(polynomials[i], srs.Pk) - assert.NoError(err) - } - - // random point at which the polynomials are evaluated - var point fr_bn254.Element - point.SetRandom() - - // build short hash, we pick a number one byte less than the snark field... - var target big.Int - target.SetUint64(1) - nbBits := ecc.BLS12_381.ScalarField().BitLen() - nn := ((nbBits+7)/8)*8 - 8 - target.Lsh(&target, uint(nn)) - h, err := recursion.NewShort(ecc.BLS12_381.ScalarField(), &target) - assert.NoError(err) - - batchOpeningProof, err := kzg_bn254.BatchOpenSinglePoint(polynomials[:], coms[:], point, h, srs.Pk) - assert.NoError(err) - - err = kzg_bn254.BatchVerifySinglePoint(coms[:], &batchOpeningProof, point, h, srs.Vk) - assert.NoError(err) - - // prepare witness - wVk, err := ValueOfVerifyingKey[sw_bn254.G1Affine, sw_bn254.G2Affine](srs.Vk) - assert.NoError(err) - wPoint, err := ValueOfScalar[emulated.BN254Fr](point) - assert.NoError(err) - var wDigests [10]Commitment[sw_bn254.G1Affine] - for i := 0; i < 10; i++ { - wDigests[i], err = ValueOfCommitment[sw_bn254.G1Affine](coms[i]) - assert.NoError(err) - } - wBatchOpeningProof, err := ValueOfBatchOpeningProof[emulated.BN254Fr, sw_bn254.G1Affine](batchOpeningProof) - assert.NoError(err) - - assignment := BatchVerifySinglePointTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ - Vk: wVk, - Point: wPoint, - Digests: wDigests, - BatchOpeningProof: wBatchOpeningProof, - } - - var circuit BatchVerifySinglePointTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl] - circuit.BatchOpeningProof.ClaimedValues = make([]emulated.Element[emulated.BN254Fr], 10) - assert.CheckCircuit(&circuit, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) - -} - -//-------------------------------------------------------- -// Batch verify multi point - -// type BatchVerifyMultiPointsTest[S emulated.FieldParams, G1El, G2El, GTEl any] struct { -// Vk VerifyingKey[G1El, G2El] -// Digests [5]Commitment[G1El] -// Proofs [5]OpeningProof[S, G1El] -// Points [5]emulated.Element[S] -// } - -type BatchVerifyMultiPointsTest[S emulated.FieldParams, G1El, G2El, GTEl any] struct { - Vk VerifyingKey[G1El, G2El] - Digests [2]Commitment[G1El] - Proofs [2]OpeningProof[S, G1El] - Points [2]emulated.Element[S] -} - -func (circuit *BatchVerifyMultiPointsTest[S, G1El, G2El, GTEl]) Define(api frontend.API) error { - - verifier, err := NewVerifier[S, G1El, G2El, GTEl](api) - if err != nil { - return fmt.Errorf("get pairing: %w", err) - } - - verifier.BatchVerifyMultiPoints(circuit.Digests[:], circuit.Proofs[:], circuit.Points[:], circuit.Vk) - - return nil -} - -func TestBatchVerifyMultiPoints(t *testing.T) { - - assert := test.NewAssert(t) - - // prepare test data - alpha, err := rand.Int(rand.Reader, ecc.BN254.ScalarField()) - assert.NoError(err) - srs, err := kzg_bn254.NewSRS(kzgSize, alpha) - assert.NoError(err) - - var polynomials [2][]fr_bn254.Element - var coms [2]kzg_bn254.Digest - for i := 0; i < 2; i++ { - polynomials[i] = make([]fr_bn254.Element, polynomialSize) - for j := 0; j < polynomialSize; j++ { - polynomials[i][j].SetRandom() - } - coms[i], err = kzg_bn254.Commit(polynomials[i], srs.Pk) - assert.NoError(err) - } - - // random points at which the polynomials are evaluated - var points [2]fr_bn254.Element - for i := 0; i < 2; i++ { - points[i].SetRandom() - } - - // build opening proofs - var openingProofs [2]kzg_bn254.OpeningProof - for i := 0; i < 2; i++ { - openingProofs[i], err = kzg_bn254.Open(polynomials[i], points[i], srs.Pk) - assert.NoError(err) - } - - // check that the proofs are correct - err = kzg_bn254.BatchVerifyMultiPoints(coms[:], openingProofs[:], points[:], srs.Vk) - assert.NoError(err) - - // prepare witness - wVk, err := ValueOfVerifyingKey[sw_bn254.G1Affine, sw_bn254.G2Affine](srs.Vk) - assert.NoError(err) - var wDigests [2]Commitment[sw_bn254.G1Affine] - var wPoints [2]emulated.Element[emulated.BN254Fr] - var wOpeningProofs [2]OpeningProof[emulated.BN254Fr, sw_bn254.G1Affine] - for i := 0; i < 2; i++ { - wPoints[i], err = ValueOfScalar[emulated.BN254Fr](points[i]) - assert.NoError(err) - wDigests[i], err = ValueOfCommitment[sw_bn254.G1Affine](coms[i]) - assert.NoError(err) - wOpeningProofs[i], err = ValueOfOpeningProof[emulated.BN254Fr, sw_bn254.G1Affine](openingProofs[i]) - assert.NoError(err) - } - - assignment := BatchVerifyMultiPointsTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ - Vk: wVk, - Points: wPoints, - Digests: wDigests, - Proofs: wOpeningProofs, - } - - var circuit BatchVerifyMultiPointsTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl] - assert.CheckCircuit(&circuit, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) - -} - -//-------------------------------------------------------- -// derive gamma - -// type DeriveGammaTest[S emulated.FieldParams, G1El, G2El, GTEl any] struct { -// Point emulated.Element[S] -// Digests [10]Commitment[G1El] -// ClaimedValues [10]emulated.Element[S] -// Gamma emulated.Element[S] -// } - -// func (circuit *DeriveGammaTest[S, G1El, G2El, GTEl]) Define(api frontend.API) error { - -// verifier, err := NewVerifier[S, G1El, G2El, GTEl](api) -// if err != nil { -// return fmt.Errorf("get pairing: %w", err) -// } - -// // pick a number on byte shorter than the modulus size -// var target big.Int -// target.SetUint64(1) -// nbBits := api.Compiler().Field().BitLen() -// nn := ((nbBits+7)/8)*8 - 8 -// target.Lsh(&target, uint(nn)) - -// // create the wrapped hash function -// whSnark, err := recursion.NewHash(api, &target, true) -// if err != nil { -// return err -// } - -// res, err := verifier.deriveGamma(circuit.Point, circuit.Digests[:], circuit.ClaimedValues[:], whSnark) -// if err != nil { -// return err -// } -// verifier.scalarApi.AssertIsEqual(&res, &circuit.Gamma) -// return nil -// } - -// func TestDeriveGamma(t *testing.T) { - -// assert := test.NewAssert(t) - -// // prepare test data -// alpha, err := rand.Int(rand.Reader, ecc.BN254.ScalarField()) -// assert.NoError(err) -// srs, err := kzg_bn254.NewSRS(kzgSize, alpha) -// assert.NoError(err) - -// var polynomials [10][]fr_bn254.Element -// var digests [10]kzg_bn254.Digest -// for i := 0; i < 10; i++ { -// polynomials[i] = make([]fr_bn254.Element, polynomialSize) -// for j := 0; j < polynomialSize; j++ { -// polynomials[i][j].SetRandom() -// } -// digests[i], err = kzg_bn254.Commit(polynomials[i], srs.Pk) -// assert.NoError(err) -// } - -// var point fr_bn254.Element -// point.SetRandom() -// var target big.Int -// target.SetUint64(1) -// nbBits := ecc.BLS12_381.ScalarField().BitLen() -// nn := ((nbBits+7)/8)*8 - 8 -// target.Lsh(&target, uint(nn)) -// h, err := recursion.NewShort(ecc.BLS12_381.ScalarField(), &target) -// assert.NoError(err) - -// batchOpeningProof, err := kzg_bn254.BatchOpenSinglePoint(polynomials[:], digests[:], point, h, srs.Pk) -// assert.NoError(err) - -// gamma, err := kzg_bn254.DeriveGamma(point, digests[:], batchOpeningProof.ClaimedValues, h) -// assert.NoError(err) - -// // prepare witness -// wPoint, err := ValueOfScalar[emulated.BN254Fr](point) -// assert.NoError(err) -// var wDigests [10]Commitment[sw_bn254.G1Affine] -// for i := 0; i < 10; i++ { -// wDigests[i], err = ValueOfCommitment[sw_bn254.G1Affine](digests[i]) -// assert.NoError(err) -// } -// var wClaimedValues [10]emulated.Element[emulated.BN254Fr] -// for i := 0; i < 10; i++ { -// wClaimedValues[i], err = ValueOfScalar[emulated.BN254Fr](batchOpeningProof.ClaimedValues[i]) -// assert.NoError(err) -// } -// wGmma, err := ValueOfScalar[emulated.BN254Fr](gamma) -// assert.NoError(err) - -// assignment := DeriveGammaTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ -// Point: wPoint, -// Digests: wDigests, -// ClaimedValues: wClaimedValues, -// Gamma: wGmma, -// } - -// assert.CheckCircuit(&DeriveGammaTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{}, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) -// } From 140cd91b7473b898e68cb6f4c508a44b55db0e82 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Tue, 7 Nov 2023 16:01:12 +0100 Subject: [PATCH 14/15] feat: random number derived from context --- std/commitments/kzg/verifier.go | 52 ++++++++++------ std/commitments/kzg/verifier_test.go | 91 +++++----------------------- 2 files changed, 47 insertions(+), 96 deletions(-) diff --git a/std/commitments/kzg/verifier.go b/std/commitments/kzg/verifier.go index 0ab2d5fe8d..bdd5d8ba1a 100644 --- a/std/commitments/kzg/verifier.go +++ b/std/commitments/kzg/verifier.go @@ -3,12 +3,14 @@ package kzg import ( "errors" "fmt" + "math/big" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra" fiatshamir "github.com/consensys/gnark/std/fiat-shamir" "github.com/consensys/gnark/std/hash" "github.com/consensys/gnark/std/math/emulated" + "github.com/consensys/gnark/std/recursion" ) var ( @@ -180,9 +182,37 @@ func (v *Verifier[S, G1El, G2El, GTEl]) BatchVerifyMultiPoints(digests []Commitm // sample random numbers λᵢ for sampling randomNumbers := make([]emulated.Element[S], len(digests)) randomNumbers[0] = emulated.ValueOf[S](1) - for i := 1; i < len(randomNumbers); i++ { - // TODO use real random numbers, follow the solidity smart contract to know which variables are used as seed - randomNumbers[i] = emulated.ValueOf[S](42) + if len(digests) > 1 { + + // pick a hash function to derive the random challenge + var target big.Int + target.SetUint64(1) + nbBits := v.api.Compiler().Field().BitLen() + nn := ((nbBits+7)/8)*8 - 8 + target.Lsh(&target, uint(nn)) + whSnark, err := recursion.NewHash(v.api, &target, true) + if err != nil { + return err + } + for i := 0; i < len(digests); i++ { + marshalledG1 := v.ec.MarshalG1(digests[i].G1El) + whSnark.Write(marshalledG1...) + marshalledG1 = v.ec.MarshalG1(proofs[i].Quotient) + whSnark.Write(marshalledG1...) + marshalledScalar := v.ec.MarshalScalar(proofs[i].ClaimedValue) + whSnark.Write(marshalledScalar...) + marshalledScalar = v.ec.MarshalScalar(points[i]) + whSnark.Write(marshalledScalar...) + } + + seed := whSnark.Sum() + binSeed := v.api.ToBinary(seed) + randomNumbers[1] = *v.scalarApi.FromBits(binSeed...) + + for i := 2; i < len(randomNumbers); i++ { + // TODO use real random numbers, follow the solidity smart contract to know which variables are used as seed + randomNumbers[i] = *v.scalarApi.Mul(&randomNumbers[1], &randomNumbers[i-1]) + } } // fold the committed quotients compute ∑ᵢλᵢ[Hᵢ(α)]G₁ @@ -219,25 +249,9 @@ func (v *Verifier[S, G1El, G2El, GTEl]) BatchVerifyMultiPoints(digests []Commitm } foldedDigests, foldedEvals := v.fold(digests, evals, randomNumbers) - // bb := v.scalarApi.ToBits(&foldedEvals) - // bbb := v.api.FromBinary(bb...) - // v.api.Println(bbb) - - // aa := v.ec.MarshalG1(foldedDigests.G1El) - // slices.Reverse(aa[:256]) - // slices.Reverse(aa[256:]) - // xx := v.api.FromBinary(aa[:256]...) - // yy := v.api.FromBinary(aa[256:]...) - // v.api.Println(xx) - // v.api.Println(yy) - // compute commitment to folded Eval [∑ᵢλᵢfᵢ(aᵢ)]G₁ foldedEvalsCommit := v.ec.ScalarMul(&vk.G1, &foldedEvals) - // bb := v.scalarApi.ToBits(&foldedEvals) - // bbb := v.api.FromBinary(bb...) - // v.api.Println(bbb) - // compute foldedDigests = ∑ᵢλᵢ[fᵢ(α)]G₁ - [∑ᵢλᵢfᵢ(aᵢ)]G₁ // foldedDigests.Sub(&foldedDigests, &foldedEvalsCommit) tmp := v.ec.Neg(foldedEvalsCommit) diff --git a/std/commitments/kzg/verifier_test.go b/std/commitments/kzg/verifier_test.go index d8b85ada45..a199bd07e9 100644 --- a/std/commitments/kzg/verifier_test.go +++ b/std/commitments/kzg/verifier_test.go @@ -89,69 +89,6 @@ func TestKZGVerificationEmulated(t *testing.T) { assert.CheckCircuit(&KZGVerificationCircuit[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{}, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) } -//-------------------------------------------------------- -// Slice proof - -// type SliceTest[S emulated.FieldParams, G1El any] struct { -// Proof BatchOpeningProof[S, G1El] -// } - -// func (circuit *SliceTest[S, G1El]) Define(api frontend.API) error { - -// fmt.Println(len(circuit.Proof.ClaimedValues)) -// return nil -// } - -// func TestSlices(t *testing.T) { - -// assert := test.NewAssert(t) - -// // prepare test data -// alpha, err := rand.Int(rand.Reader, ecc.BN254.ScalarField()) -// assert.NoError(err) -// srs, err := kzg_bn254.NewSRS(kzgSize, alpha) -// assert.NoError(err) - -// var polynomials [10][]fr_bn254.Element -// var coms [10]kzg_bn254.Digest -// for i := 0; i < 10; i++ { -// polynomials[i] = make([]fr_bn254.Element, polynomialSize) -// for j := 0; j < polynomialSize; j++ { -// polynomials[i][j].SetRandom() -// } -// coms[i], err = kzg_bn254.Commit(polynomials[i], srs.Pk) -// assert.NoError(err) -// } - -// var point fr_bn254.Element -// point.SetRandom() -// var target big.Int -// target.SetUint64(1) -// nbBits := ecc.BLS12_381.ScalarField().BitLen() -// nn := ((nbBits+7)/8)*8 - 8 -// target.Lsh(&target, uint(nn)) -// h, err := recursion.NewShort(ecc.BLS12_381.ScalarField(), &target) -// assert.NoError(err) - -// batchOpeningProof, err := kzg_bn254.BatchOpenSinglePoint(polynomials[:], coms[:], point, h, srs.Pk) -// assert.NoError(err) - -// _, _, err = kzg_bn254.FoldProof(coms[:], &batchOpeningProof, point, h) -// assert.NoError(err) - -// // circuit -// var circuit SliceTest[emulated.BN254Fr, sw_bn254.G1Affine] -// circuit.Proof.ClaimedValues = make([]emulated.Element[emulated.BN254Fr], 10) - -// var assignment SliceTest[emulated.BN254Fr, sw_bn254.G1Affine] -// // assignment.Proof.ClaimedValues = make([]emulated.Element[emulated.BN254Fr], 10) -// assignment.Proof, err = ValueOfBatchOpeningProof[emulated.BN254Fr, sw_bn254.G1Affine](batchOpeningProof) -// assert.NoError(err) - -// assert.CheckCircuit(&circuit, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) - -// } - //-------------------------------------------------------- // Fold proof @@ -376,9 +313,9 @@ func TestBatchVerifySinglePoint(t *testing.T) { type BatchVerifyMultiPointsTest[S emulated.FieldParams, G1El, G2El, GTEl any] struct { Vk VerifyingKey[G1El, G2El] - Digests [2]Commitment[G1El] - Proofs [2]OpeningProof[S, G1El] - Points [2]emulated.Element[S] + Digests [4]Commitment[G1El] + Proofs [4]OpeningProof[S, G1El] + Points [4]emulated.Element[S] } func (circuit *BatchVerifyMultiPointsTest[S, G1El, G2El, GTEl]) Define(api frontend.API) error { @@ -403,9 +340,9 @@ func TestBatchVerifyMultiPoints(t *testing.T) { srs, err := kzg_bn254.NewSRS(kzgSize, alpha) assert.NoError(err) - var polynomials [2][]fr_bn254.Element - var coms [2]kzg_bn254.Digest - for i := 0; i < 2; i++ { + var polynomials [4][]fr_bn254.Element + var coms [4]kzg_bn254.Digest + for i := 0; i < 4; i++ { polynomials[i] = make([]fr_bn254.Element, polynomialSize) for j := 0; j < polynomialSize; j++ { polynomials[i][j].SetRandom() @@ -415,14 +352,14 @@ func TestBatchVerifyMultiPoints(t *testing.T) { } // random points at which the polynomials are evaluated - var points [2]fr_bn254.Element - for i := 0; i < 2; i++ { + var points [4]fr_bn254.Element + for i := 0; i < 4; i++ { points[i].SetRandom() } // build opening proofs - var openingProofs [2]kzg_bn254.OpeningProof - for i := 0; i < 2; i++ { + var openingProofs [4]kzg_bn254.OpeningProof + for i := 0; i < 4; i++ { openingProofs[i], err = kzg_bn254.Open(polynomials[i], points[i], srs.Pk) assert.NoError(err) } @@ -434,10 +371,10 @@ func TestBatchVerifyMultiPoints(t *testing.T) { // prepare witness wVk, err := ValueOfVerifyingKey[sw_bn254.G1Affine, sw_bn254.G2Affine](srs.Vk) assert.NoError(err) - var wDigests [2]Commitment[sw_bn254.G1Affine] - var wPoints [2]emulated.Element[emulated.BN254Fr] - var wOpeningProofs [2]OpeningProof[emulated.BN254Fr, sw_bn254.G1Affine] - for i := 0; i < 2; i++ { + var wDigests [4]Commitment[sw_bn254.G1Affine] + var wPoints [4]emulated.Element[emulated.BN254Fr] + var wOpeningProofs [4]OpeningProof[emulated.BN254Fr, sw_bn254.G1Affine] + for i := 0; i < 4; i++ { wPoints[i], err = ValueOfScalar[emulated.BN254Fr](points[i]) assert.NoError(err) wDigests[i], err = ValueOfCommitment[sw_bn254.G1Affine](coms[i]) From a75c3cddb940ad614bdd108e2dd0cf30f4c7866c Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Tue, 7 Nov 2023 16:14:13 +0100 Subject: [PATCH 15/15] clean: remove commented code --- std/commitments/kzg/verifier.go | 6 -- std/commitments/kzg/verifier_test.go | 101 --------------------------- 2 files changed, 107 deletions(-) diff --git a/std/commitments/kzg/verifier.go b/std/commitments/kzg/verifier.go index bdd5d8ba1a..1d08916083 100644 --- a/std/commitments/kzg/verifier.go +++ b/std/commitments/kzg/verifier.go @@ -140,12 +140,6 @@ func (v *Verifier[S, G1El, G2El, GTEl]) FoldProof(digests []Commitment[G1El], ba foldedProof.ClaimedValue = foldedEvaluations return foldedProof, foldedDigests, nil - // create the folded opening proof - // var res OpeningProof[S, G1El] - // res.ClaimedValue = batchOpeningProof.ClaimedValues[0] - // res.Quotient = batchOpeningProof.Quotient - // return res, digests[0], nil - } func (v *Verifier[S, G1El, G2El, GTEl]) BatchVerifySinglePoint(digests []Commitment[G1El], batchOpeningProof BatchOpeningProof[S, G1El], point emulated.Element[S], hf hash.FieldHasher, vk VerifyingKey[G1El, G2El], dataTranscript ...frontend.Variable) error { diff --git a/std/commitments/kzg/verifier_test.go b/std/commitments/kzg/verifier_test.go index a199bd07e9..d633c2a1d8 100644 --- a/std/commitments/kzg/verifier_test.go +++ b/std/commitments/kzg/verifier_test.go @@ -394,104 +394,3 @@ func TestBatchVerifyMultiPoints(t *testing.T) { assert.CheckCircuit(&circuit, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) } - -//-------------------------------------------------------- -// derive gamma - -// type DeriveGammaTest[S emulated.FieldParams, G1El, G2El, GTEl any] struct { -// Point emulated.Element[S] -// Digests [10]Commitment[G1El] -// ClaimedValues [10]emulated.Element[S] -// Gamma emulated.Element[S] -// } - -// func (circuit *DeriveGammaTest[S, G1El, G2El, GTEl]) Define(api frontend.API) error { - -// verifier, err := NewVerifier[S, G1El, G2El, GTEl](api) -// if err != nil { -// return fmt.Errorf("get pairing: %w", err) -// } - -// // pick a number on byte shorter than the modulus size -// var target big.Int -// target.SetUint64(1) -// nbBits := api.Compiler().Field().BitLen() -// nn := ((nbBits+7)/8)*8 - 8 -// target.Lsh(&target, uint(nn)) - -// // create the wrapped hash function -// whSnark, err := recursion.NewHash(api, &target, true) -// if err != nil { -// return err -// } - -// res, err := verifier.deriveGamma(circuit.Point, circuit.Digests[:], circuit.ClaimedValues[:], whSnark) -// if err != nil { -// return err -// } -// verifier.scalarApi.AssertIsEqual(&res, &circuit.Gamma) -// return nil -// } - -// func TestDeriveGamma(t *testing.T) { - -// assert := test.NewAssert(t) - -// // prepare test data -// alpha, err := rand.Int(rand.Reader, ecc.BN254.ScalarField()) -// assert.NoError(err) -// srs, err := kzg_bn254.NewSRS(kzgSize, alpha) -// assert.NoError(err) - -// var polynomials [10][]fr_bn254.Element -// var digests [10]kzg_bn254.Digest -// for i := 0; i < 10; i++ { -// polynomials[i] = make([]fr_bn254.Element, polynomialSize) -// for j := 0; j < polynomialSize; j++ { -// polynomials[i][j].SetRandom() -// } -// digests[i], err = kzg_bn254.Commit(polynomials[i], srs.Pk) -// assert.NoError(err) -// } - -// var point fr_bn254.Element -// point.SetRandom() -// var target big.Int -// target.SetUint64(1) -// nbBits := ecc.BLS12_381.ScalarField().BitLen() -// nn := ((nbBits+7)/8)*8 - 8 -// target.Lsh(&target, uint(nn)) -// h, err := recursion.NewShort(ecc.BLS12_381.ScalarField(), &target) -// assert.NoError(err) - -// batchOpeningProof, err := kzg_bn254.BatchOpenSinglePoint(polynomials[:], digests[:], point, h, srs.Pk) -// assert.NoError(err) - -// gamma, err := kzg_bn254.DeriveGamma(point, digests[:], batchOpeningProof.ClaimedValues, h) -// assert.NoError(err) - -// // prepare witness -// wPoint, err := ValueOfScalar[emulated.BN254Fr](point) -// assert.NoError(err) -// var wDigests [10]Commitment[sw_bn254.G1Affine] -// for i := 0; i < 10; i++ { -// wDigests[i], err = ValueOfCommitment[sw_bn254.G1Affine](digests[i]) -// assert.NoError(err) -// } -// var wClaimedValues [10]emulated.Element[emulated.BN254Fr] -// for i := 0; i < 10; i++ { -// wClaimedValues[i], err = ValueOfScalar[emulated.BN254Fr](batchOpeningProof.ClaimedValues[i]) -// assert.NoError(err) -// } -// wGmma, err := ValueOfScalar[emulated.BN254Fr](gamma) -// assert.NoError(err) - -// assignment := DeriveGammaTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{ -// Point: wPoint, -// Digests: wDigests, -// ClaimedValues: wClaimedValues, -// Gamma: wGmma, -// } - -// assert.CheckCircuit(&DeriveGammaTest[emulated.BN254Fr, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{}, test.WithValidAssignment(&assignment), test.WithCurves(ecc.BLS12_381), test.WithBackends(backend.PLONK)) -// }