From c67b65c52448ecfa5e7f5a6f0fd5fe42818f2436 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 3 Nov 2023 13:18:10 +0100 Subject: [PATCH] WIP PLONK --- std/recursion/plonk/verifier.go | 122 +++++++++++++-------------- std/recursion/plonk/verifier_test.go | 25 +++--- 2 files changed, 74 insertions(+), 73 deletions(-) diff --git a/std/recursion/plonk/verifier.go b/std/recursion/plonk/verifier.go index daa9138b21..d360868d05 100644 --- a/std/recursion/plonk/verifier.go +++ b/std/recursion/plonk/verifier.go @@ -21,10 +21,10 @@ import ( 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/math/emulated/emparams" + "github.com/consensys/gnark/std/recursion" ) -type Proof[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT] struct { +type Proof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT] struct { // Commitments to the solution vectors LRO [3]kzg.Commitment[G1El] // Commitment to Z, the permutation polynomial @@ -35,17 +35,17 @@ type Proof[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT] Bsb22Commitments []kzg.Commitment[G1El] // Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime - BatchedProof kzg.BatchOpeningProof[S, G1El] + BatchedProof kzg.BatchOpeningProof[FR, G1El] // Opening proof of Z at zeta*mu - ZShiftedOpening kzg.OpeningProof[S, G1El] + ZShiftedOpening kzg.OpeningProof[FR, G1El] } -func ValueOfProof[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT](proof backend_plonk.Proof) (Proof[S, G1El, G2El], error) { - var ret Proof[S, G1El, G2El] +func ValueOfProof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT](proof backend_plonk.Proof) (Proof[FR, G1El, G2El], error) { + var ret Proof[FR, G1El, G2El] var err error switch r := any(&ret).(type) { - case *Proof[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine]: + case *Proof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine]: tProof, ok := proof.(*plonkbackend_bls12377.Proof) if !ok { return ret, fmt.Errorf("expected sw_bls12377.Proof, got %T", proof) @@ -74,11 +74,11 @@ func ValueOfProof[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2Ele } } // TODO: actually we compute the opening point later. Maybe we can precompute it here and later assert its correctness? - r.BatchedProof, err = kzg.ValueOfBatchOpeningProof[sw_bls12377.Scalar, sw_bls12377.G1Affine]([]fr_bls12377.Element{}, tProof.BatchedProof) + r.BatchedProof, err = kzg.ValueOfBatchOpeningProof[sw_bls12377.ScalarField, sw_bls12377.G1Affine]([]fr_bls12377.Element{}, tProof.BatchedProof) if err != nil { return ret, fmt.Errorf("batch opening proof value assignment: %w", err) } - r.ZShiftedOpening, err = kzg.ValueOfOpeningProof[sw_bls12377.Scalar, sw_bls12377.G1Affine](fr_bls12377.One(), tProof.ZShiftedOpening) + r.ZShiftedOpening, err = kzg.ValueOfOpeningProof[sw_bls12377.ScalarField, sw_bls12377.G1Affine](fr_bls12377.One(), tProof.ZShiftedOpening) if err != nil { return ret, fmt.Errorf("z shifted opening proof value assignment: %w", err) } @@ -88,27 +88,27 @@ func ValueOfProof[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2Ele return ret, nil } -func PlaceholderProof[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT](ccs constraint.ConstraintSystem) Proof[S, G1El, G2El] { - return Proof[S, G1El, G2El]{ - BatchedProof: kzg.BatchOpeningProof[S, G1El]{ - ClaimedValues: make([]S, 7), - Points: []S{}, +func PlaceholderProof[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT](ccs constraint.ConstraintSystem) Proof[FR, G1El, G2El] { + return Proof[FR, G1El, G2El]{ + BatchedProof: kzg.BatchOpeningProof[FR, G1El]{ + ClaimedValues: make([]emulated.Element[FR], 7), + Points: []emulated.Element[FR]{}, }, } } -type VerifyingKey[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT] struct { +type VerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT] struct { // Size circuit - Size S - SizeInv S - Generator S + Size emulated.Element[FR] + SizeInv emulated.Element[FR] + Generator emulated.Element[FR] NbPublicVariables uint64 // Commitment scheme that is used for an instantiation of PLONK Kzg kzg.VerifyingKey[G2El] // cosetShift generator of the coset on the small domain - CosetShift S + CosetShift emulated.Element[FR] // S commitments to S1, S2, S3 S [3]kzg.Commitment[G1El] @@ -122,16 +122,16 @@ type VerifyingKey[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2Ele CommitmentConstraintIndexes []uint64 } -func ValueOfVerifyingKey[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT](vk backend_plonk.VerifyingKey) (VerifyingKey[S, G1El, G2El], error) { - var ret VerifyingKey[S, G1El, G2El] +func ValueOfVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT](vk backend_plonk.VerifyingKey) (VerifyingKey[FR, G1El, G2El], error) { + var ret VerifyingKey[FR, G1El, G2El] var err error switch r := any(&ret).(type) { - case *VerifyingKey[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine]: + case *VerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine]: tVk, ok := vk.(*plonkbackend_bls12377.VerifyingKey) if !ok { return ret, fmt.Errorf("expected bls12377.VerifyingKey, got %T", vk) } - r.Size = tVk.Size + r.Size = emulated.ValueOf[sw_bls12377.ScalarField](tVk.Size) r.SizeInv = sw_bls12377.NewScalar(tVk.SizeInv) r.Generator = sw_bls12377.NewScalar(tVk.Generator) r.NbPublicVariables = tVk.NbPublicVariables @@ -181,82 +181,79 @@ func ValueOfVerifyingKey[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebr return ret, nil } -func PlaceholderVerifyingKey[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT](ccs constraint.ConstraintSystem) VerifyingKey[S, G1El, G2El] { +func PlaceholderVerifyingKey[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT](ccs constraint.ConstraintSystem) VerifyingKey[FR, G1El, G2El] { // TODO: we're not considering the commitments right now - var ret VerifyingKey[S, G1El, G2El] + var ret VerifyingKey[FR, G1El, G2El] return ret } // Witness is a public witness to verify the SNARK proof against. For assigning // witness use [ValueOfWitness] and to create stub witness for compiling use // [PlaceholderWitness]. -type Witness[S algebra.ScalarT] struct { +type Witness[FR emulated.FieldParams] struct { // Public is the public inputs. The first element does not need to be one // wire and is added implicitly during verification. - Public []S + Public []emulated.Element[FR] } -func ValueOfWitness[S algebra.ScalarT, G1 algebra.G1ElementT](w witness.Witness) (Witness[S], error) { - type dbwtiness[S algebra.ScalarT, G1 algebra.G1ElementT] struct { - W Witness[S] - } - var ret dbwtiness[S, G1] +func ValueOfWitness[FR emulated.FieldParams](w witness.Witness) (Witness[FR], error) { + var ret Witness[FR] pubw, err := w.Public() if err != nil { - return ret.W, fmt.Errorf("get public witness: %w", err) + return ret, fmt.Errorf("get public witness: %w", err) } vec := pubw.Vector() switch s := any(&ret).(type) { - case *dbwtiness[emulated.Element[emparams.BN254Fr], sw_bn254.G1Affine]: + case *Witness[sw_bn254.ScalarField]: vect, ok := vec.(fr_bn254.Vector) if !ok { - return ret.W, fmt.Errorf("expected fr_bn254.Vector, got %T", vec) + return ret, fmt.Errorf("expected fr_bn254.Vector, got %T", vec) } for i := range vect { - s.W.Public = append(s.W.Public, emulated.ValueOf[emparams.BN254Fr](vect[i])) + s.Public = append(s.Public, sw_bn254.NewScalar(vect[i])) } - case *dbwtiness[sw_bls12377.Scalar, sw_bls12377.G1Affine]: + case *Witness[sw_bls12377.ScalarField]: vect, ok := vec.(fr_bls12377.Vector) if !ok { - return ret.W, fmt.Errorf("expected fr_bls12377.Vector, got %T", vec) + return ret, fmt.Errorf("expected fr_bls12377.Vector, got %T", vec) } for i := range vect { - s.W.Public = append(s.W.Public, vect[i].String()) + s.Public = append(s.Public, sw_bls12377.NewScalar(vect[i])) } - case *dbwtiness[emulated.Element[emparams.BLS12381Fr], sw_bls12381.G1Affine]: + case *Witness[sw_bls12381.ScalarField]: vect, ok := vec.(fr_bls12381.Vector) if !ok { - return ret.W, fmt.Errorf("expected fr_bls12381.Vector, got %T", vec) + return ret, fmt.Errorf("expected fr_bls12381.Vector, got %T", vec) } for i := range vect { - s.W.Public = append(s.W.Public, emulated.ValueOf[emparams.BLS12381Fr](vect[i])) + s.Public = append(s.Public, sw_bls12381.NewScalar(vect[i])) } - case *dbwtiness[sw_bls24315.Scalar, sw_bls24315.G1Affine]: + case *Witness[sw_bls24315.ScalarField]: vect, ok := vec.(fr_bls24315.Vector) if !ok { - return ret.W, fmt.Errorf("expected fr_bls24315.Vector, got %T", vec) + return ret, fmt.Errorf("expected fr_bls24315.Vector, got %T", vec) } for i := range vect { - s.W.Public = append(s.W.Public, vect[i].String()) + s.Public = append(s.Public, sw_bls24315.NewScalar(vect[i])) } default: - return ret.W, fmt.Errorf("unknown parametric type combination") + return ret, fmt.Errorf("unknown parametric type combination") } - return ret.W, nil + return ret, nil } // PlaceholderWitness creates a stub witness which can be used to allocate the // variables in the circuit if the actual witness is not yet known. It takes // into account the number of public inputs and number of used commitments. -func PlaceholderWitness[S algebra.ScalarT](ccs constraint.ConstraintSystem) Witness[S] { - return Witness[S]{ - Public: make([]S, ccs.GetNbPublicVariables()), +func PlaceholderWitness[FR emulated.FieldParams](ccs constraint.ConstraintSystem) Witness[FR] { + return Witness[FR]{ + Public: make([]emulated.Element[FR], ccs.GetNbPublicVariables()), } } -type Verifier[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT] struct { +type Verifier[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT] struct { api frontend.API - curve algebra.Curve[S, G1El] + curve algebra.Curve[FR, G1El] pairing algebra.Pairing[G1El, G2El, GtEl] kzgHash hash.FieldHasher fsHash hash.FieldHasher @@ -264,10 +261,10 @@ type Verifier[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2Element } func NewVerifier[ - S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT]( - api frontend.API, curve algebra.Curve[S, G1El], pairing algebra.Pairing[G1El, G2El, GtEl], - fsHash hash.FieldHasher) *Verifier[S, G1El, G2El, GtEl] { - return &Verifier[S, G1El, G2El, GtEl]{ + FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT]( + api frontend.API, curve algebra.Curve[FR, G1El], pairing algebra.Pairing[G1El, G2El, GtEl], + fsHash hash.FieldHasher) *Verifier[FR, G1El, G2El, GtEl] { + return &Verifier[FR, G1El, G2El, GtEl]{ api: api, curve: curve, pairing: pairing, @@ -275,11 +272,14 @@ func NewVerifier[ } } -func (v *Verifier[S, G1El, G2El, GtEl]) AssertProof(vk VerifyingKey[S, G1El, G2El], proof Proof[S, G1El, G2El], witness Witness[S]) error { +func (v *Verifier[FR, G1El, G2El, GtEl]) AssertProof(vk VerifyingKey[FR, G1El, G2El], proof Proof[FR, G1El, G2El], witness Witness[FR]) error { if len(proof.Bsb22Commitments) != len(vk.Qcp) { return fmt.Errorf("BSB22 commitment number mismatch") } - fs := fiatshamir.NewTranscript(v.api, v.fsHash, []string{"gamma", "beta", "alpha", "zeta"}) + fs, err := recursion.NewTranscript(v.api, nil, []string{"gamma", "beta", "alpha", "zeta"}) + if err != nil { + return fmt.Errorf("init new transcript: %w", err) + } if err := v.bindPublicData(fs, "gamma", vk, witness); err != nil { return fmt.Errorf("bind public data: %w", err) @@ -519,7 +519,7 @@ func (v *Verifier[S, G1El, G2El, GtEl]) AssertProof(vk VerifyingKey[S, G1El, G2E return nil } -func (v *Verifier[S, G1El, G2El, GtEl]) bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey[S, G1El, G2El], witness Witness[S]) error { +func (v *Verifier[FR, G1El, G2El, GtEl]) bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey[FR, G1El, G2El], witness Witness[FR]) error { // permutation if err := fs.Bind(challenge, v.curve.MarshalG1(vk.S[0].G1El)); err != nil { return err @@ -563,8 +563,8 @@ func (v *Verifier[S, G1El, G2El, GtEl]) bindPublicData(fs *fiatshamir.Transcript return nil } -func (v *Verifier[S, G1El, G2El, GtEl]) deriveRandomness(fs *fiatshamir.Transcript, challenge string, points ...G1El) (S, error) { - var ret S +func (v *Verifier[FR, G1El, G2El, GtEl]) deriveRandomness(fs *fiatshamir.Transcript, challenge string, points ...G1El) (emulated.Element[FR], error) { + var ret emulated.Element[FR] for i := range points { if err := fs.Bind(challenge, v.curve.MarshalG1(points[i])); err != nil { return ret, fmt.Errorf("bind challenge %d: %w", i, err) diff --git a/std/recursion/plonk/verifier_test.go b/std/recursion/plonk/verifier_test.go index 83dc9c6c3e..4d394d0692 100644 --- a/std/recursion/plonk/verifier_test.go +++ b/std/recursion/plonk/verifier_test.go @@ -14,6 +14,7 @@ import ( "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/std/algebra" "github.com/consensys/gnark/std/algebra/native/sw_bls12377" + "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/std/recursion" "github.com/consensys/gnark/test" ) @@ -58,10 +59,10 @@ func getInner(assert *test.Assert, field, outer *big.Int) (constraint.Constraint return innerCcs, innerVK, innerPubWitness, innerProof } -type OuterCircuit[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT] struct { - Proof Proof[S, G1El, G2El] - VerifyingKey VerifyingKey[S, G1El, G2El] - InnerWitness Witness[S] +type OuterCircuit[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT] struct { + Proof Proof[FR, G1El, G2El] + VerifyingKey VerifyingKey[FR, G1El, G2El] + InnerWitness Witness[FR] target *big.Int // TODO: remove later } @@ -90,20 +91,20 @@ func TestBLS12InBW6(t *testing.T) { innerCcs, innerVK, innerWitness, innerProof := getInner(assert, ecc.BLS12_377.ScalarField(), ecc.BW6_761.ScalarField()) // outer proof - circuitVk, err := ValueOfVerifyingKey[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerVK) + circuitVk, err := ValueOfVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerVK) assert.NoError(err) - circuitWitness, err := ValueOfWitness[sw_bls12377.Scalar, sw_bls12377.G1Affine](innerWitness) + circuitWitness, err := ValueOfWitness[sw_bls12377.ScalarField](innerWitness) assert.NoError(err) - circuitProof, err := ValueOfProof[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerProof) + circuitProof, err := ValueOfProof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerProof) assert.NoError(err) - outerCircuit := &OuterCircuit[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ - InnerWitness: PlaceholderWitness[sw_bls12377.Scalar](innerCcs), - Proof: PlaceholderProof[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerCcs), - VerifyingKey: PlaceholderVerifyingKey[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerCcs), + outerCircuit := &OuterCircuit[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ + InnerWitness: PlaceholderWitness[sw_bls12377.ScalarField](innerCcs), + Proof: PlaceholderProof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerCcs), + VerifyingKey: PlaceholderVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerCcs), target: ecc.BLS12_377.ScalarField(), } - outerAssignment := &OuterCircuit[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ + outerAssignment := &OuterCircuit[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ InnerWitness: circuitWitness, Proof: circuitProof, VerifyingKey: circuitVk,