diff --git a/std/recursion/plonk/temp.go b/std/recursion/plonk/temp.go deleted file mode 100644 index b9fbc7578b..0000000000 --- a/std/recursion/plonk/temp.go +++ /dev/null @@ -1,11 +0,0 @@ -package plonk - -import ( - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/algebra" -) - -func marshalG1[G1El algebra.G1ElementT](api frontend.API, p G1El) []frontend.Variable { - // TODO - return []frontend.Variable{} -} diff --git a/std/recursion/plonk/verifier.go b/std/recursion/plonk/verifier.go index 37ccca224e..30c7ca8cf7 100644 --- a/std/recursion/plonk/verifier.go +++ b/std/recursion/plonk/verifier.go @@ -3,19 +3,30 @@ package plonk import ( "fmt" + fr_bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + fr_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + fr_bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315/fr" + fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr" backend_plonk "github.com/consensys/gnark/backend/plonk" + plonkbackend_bls12377 "github.com/consensys/gnark/backend/plonk/bls12-377" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/algebra" + "github.com/consensys/gnark/std/algebra/emulated/sw_bls12381" + "github.com/consensys/gnark/std/algebra/emulated/sw_bn254" + "github.com/consensys/gnark/std/algebra/native/sw_bls12377" + "github.com/consensys/gnark/std/algebra/native/sw_bls24315" "github.com/consensys/gnark/std/commitments/kzg" fiatshamir "github.com/consensys/gnark/std/fiat-shamir" "github.com/consensys/gnark/std/hash" + "github.com/consensys/gnark/std/math/emulated" + "github.com/consensys/gnark/std/math/emulated/emparams" ) type Proof[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT] struct { // Commitments to the solution vectors - L, R, O kzg.Commitment[G1El] + LRO [3]kzg.Commitment[G1El] // Commitment to Z, the permutation polynomial Z kzg.Commitment[G1El] // Commitments to h1, h2, h3 such that h = h1 + Xh2 + X**2h3 is the quotient polynomial @@ -24,7 +35,7 @@ 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.OpeningProof[S, G1El] // actually batch opening proof + BatchedProof kzg.BatchOpeningProof[S, G1El] // Opening proof of Z at zeta*mu ZShiftedOpening kzg.OpeningProof[S, G1El] @@ -32,9 +43,60 @@ type Proof[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT] 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] + var err error + switch r := any(&ret).(type) { + case *Proof[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine]: + tProof, ok := proof.(*plonkbackend_bls12377.Proof) + if !ok { + return ret, fmt.Errorf("expected sw_bls12377.Proof, got %T", proof) + } + for i := range r.LRO { + r.LRO[i], err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tProof.LRO[i]) + if err != nil { + return ret, fmt.Errorf("commitment LRO[%d] value assignment: %w", i, err) + } + } + r.Z, err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tProof.Z) + if err != nil { + return ret, fmt.Errorf("commitment Z value assignment: %w", err) + } + for i := range r.H { + r.H[i], err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tProof.H[i]) + if err != nil { + return ret, fmt.Errorf("commitment H[%d] value assignment: %w", i, err) + } + } + r.Bsb22Commitments = make([]kzg.Commitment[sw_bls12377.G1Affine], len(tProof.Bsb22Commitments)) + for i := range r.Bsb22Commitments { + r.Bsb22Commitments[i], err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tProof.Bsb22Commitments[i]) + if err != nil { + return ret, fmt.Errorf("bsb22 commitment %d value assignment: %w", i, err) + } + } + // TODO: actually we compute the opening point later. Maybe we can precompute it here and later assert its correctness? + r.BatchedProof, err = kzg.ValueOfBatchOpeningProof[sw_bls12377.Scalar, 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) + if err != nil { + return ret, fmt.Errorf("z shifted opening proof value assignment: %w", err) + } + default: + return ret, fmt.Errorf("unknown parametric type combination") + } 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{}, + }, + } +} + type VerifyingKey[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT] struct { // Size circuit Size S @@ -61,11 +123,68 @@ type VerifyingKey[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2Ele } func ValueOfVerifyingKey[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT](vk backend_plonk.VerifyingKey) (VerifyingKey[S, G1El, G2El], error) { - panic("TODO") + var ret VerifyingKey[S, G1El, G2El] + var err error + switch r := any(&ret).(type) { + case *VerifyingKey[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine]: + tVk, ok := vk.(*plonkbackend_bls12377.VerifyingKey) + if !ok { + return ret, fmt.Errorf("expected bls12377.VerifyingKey, got %T", vk) + } + r.Size = tVk.Size + r.SizeInv = sw_bls12377.NewScalar(tVk.SizeInv) + r.Generator = sw_bls12377.NewScalar(tVk.Generator) + r.NbPublicVariables = tVk.NbPublicVariables + r.Kzg, err = kzg.ValueOfVerifyingKey[sw_bls12377.G2Affine](tVk.Kzg) + if err != nil { + return ret, fmt.Errorf("verifying key witness assignment: %w", err) + } + r.CosetShift = sw_bls12377.NewScalar(tVk.CosetShift) + for i := range r.S { + r.S[i], err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tVk.S[i]) + if err != nil { + return ret, fmt.Errorf("commitment S[%d] witness assignment: %w", i, err) + } + } + r.Ql, err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tVk.Ql) + if err != nil { + return ret, fmt.Errorf("commitment Ql witness assignment: %w", err) + } + r.Qr, err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tVk.Qr) + if err != nil { + return ret, fmt.Errorf("commitment Qr witness assignment: %w", err) + } + r.Qm, err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tVk.Qm) + if err != nil { + return ret, fmt.Errorf("commitment Qm witness assignment: %w", err) + } + r.Qo, err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tVk.Qo) + if err != nil { + return ret, fmt.Errorf("commitment Qo witness assignment: %w", err) + } + r.Qk, err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tVk.Qk) + if err != nil { + return ret, fmt.Errorf("commitment Qk witness assignment: %w", err) + } + r.Qcp = make([]kzg.Commitment[sw_bls12377.G1Affine], len(tVk.Qcp)) + for i := range r.Qcp { + r.Qcp[i], err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tVk.Qcp[i]) + if err != nil { + return ret, fmt.Errorf("commitment Qcp[%d] witness assignment: %w", i, err) + } + } + r.CommitmentConstraintIndexes = make([]uint64, len(tVk.CommitmentConstraintIndexes)) + copy(r.CommitmentConstraintIndexes, tVk.CommitmentConstraintIndexes) + default: + return ret, fmt.Errorf("unknown parametric type combination") + } + return ret, nil } func PlaceholderVerifyingKey[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT](ccs constraint.ConstraintSystem) VerifyingKey[S, G1El, G2El] { - panic("TODO") + // TODO: we're not considering the commitments right now + var ret VerifyingKey[S, G1El, G2El] + return ret } // Witness is a public witness to verify the SNARK proof against. For assigning @@ -78,7 +197,52 @@ type Witness[S algebra.ScalarT] struct { } func ValueOfWitness[S algebra.ScalarT, G1 algebra.G1ElementT](w witness.Witness) (Witness[S], error) { - panic("TODO") + type dbwtiness[S algebra.ScalarT, G1 algebra.G1ElementT] struct { + W Witness[S] + } + var ret dbwtiness[S, G1] + pubw, err := w.Public() + if err != nil { + return ret.W, fmt.Errorf("get public witness: %w", err) + } + vec := pubw.Vector() + switch s := any(&ret).(type) { + case *dbwtiness[emulated.Element[emparams.BN254Fr], sw_bn254.G1Affine]: + vect, ok := vec.(fr_bn254.Vector) + if !ok { + return ret.W, 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])) + } + case *dbwtiness[sw_bls12377.Scalar, sw_bls12377.G1Affine]: + vect, ok := vec.(fr_bls12377.Vector) + if !ok { + return ret.W, fmt.Errorf("expected fr_bls12377.Vector, got %T", vec) + } + for i := range vect { + s.W.Public = append(s.W.Public, vect[i].String()) + } + case *dbwtiness[emulated.Element[emparams.BLS12381Fr], sw_bls12381.G1Affine]: + vect, ok := vec.(fr_bls12381.Vector) + if !ok { + return ret.W, 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])) + } + case *dbwtiness[sw_bls24315.Scalar, sw_bls24315.G1Affine]: + vect, ok := vec.(fr_bls24315.Vector) + if !ok { + return ret.W, fmt.Errorf("expected fr_bls24315.Vector, got %T", vec) + } + for i := range vect { + s.W.Public = append(s.W.Public, vect[i].String()) + } + default: + return ret.W, fmt.Errorf("unknown parametric type combination") + } + return ret.W, nil } // PlaceholderWitness creates a stub witness which can be used to allocate the @@ -86,7 +250,7 @@ func ValueOfWitness[S algebra.ScalarT, G1 algebra.G1ElementT](w witness.Witness) // 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()-1), + Public: make([]S, ccs.GetNbPublicVariables()), } } @@ -99,10 +263,15 @@ type Verifier[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2Element htfHash hash.FieldHasher } -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]) *Verifier[S, G1El, G2El, GtEl] { +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]{ + api: api, curve: curve, pairing: pairing, + fsHash: fsHash, } } @@ -121,43 +290,43 @@ func (v *Verifier[S, G1El, G2El, GtEl]) AssertProof(vk VerifyingKey[S, G1El, G2E } func (v *Verifier[S, G1El, G2El, GtEl]) bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey[S, G1El, G2El], witness Witness[S]) error { - + nbBits := v.api.Compiler().FieldBitLen() // permutation - if err := fs.Bind(challenge, marshalG1(v.api, vk.S[0])); err != nil { + if err := fs.Bind(challenge, v.curve.MarshalG1(vk.S[0].G1El, nbBits)); err != nil { return err } - if err := fs.Bind(challenge, marshalG1(v.api, vk.S[1])); err != nil { + if err := fs.Bind(challenge, v.curve.MarshalG1(vk.S[1].G1El, nbBits)); err != nil { return err } - if err := fs.Bind(challenge, marshalG1(v.api, vk.S[2])); err != nil { + if err := fs.Bind(challenge, v.curve.MarshalG1(vk.S[2].G1El, nbBits)); err != nil { return err } // coefficients - if err := fs.Bind(challenge, marshalG1(v.api, vk.Ql)); err != nil { + if err := fs.Bind(challenge, v.curve.MarshalG1(vk.Ql.G1El, nbBits)); err != nil { return err } - if err := fs.Bind(challenge, marshalG1(v.api, vk.Qr)); err != nil { + if err := fs.Bind(challenge, v.curve.MarshalG1(vk.Qr.G1El, nbBits)); err != nil { return err } - if err := fs.Bind(challenge, marshalG1(v.api, vk.Qm)); err != nil { + if err := fs.Bind(challenge, v.curve.MarshalG1(vk.Qm.G1El, nbBits)); err != nil { return err } - if err := fs.Bind(challenge, marshalG1(v.api, vk.Qo)); err != nil { + if err := fs.Bind(challenge, v.curve.MarshalG1(vk.Qo.G1El, nbBits)); err != nil { return err } - if err := fs.Bind(challenge, marshalG1(v.api, vk.Qk)); err != nil { + if err := fs.Bind(challenge, v.curve.MarshalG1(vk.Qk.G1El, nbBits)); err != nil { return err } for i := range vk.Qcp { - if err := fs.Bind(challenge, marshalG1(v.api, vk.Qcp[i])); err != nil { + if err := fs.Bind(challenge, v.curve.MarshalG1(vk.Qcp[i].G1El, nbBits)); err != nil { return err } } // public inputs for i := 0; i < len(witness.Public); i++ { - if err := fs.Bind(challenge, marshalG1(v.api, witness.Public[i])); err != nil { + if err := fs.Bind(challenge, v.curve.MarshalScalar(witness.Public[i], nbBits)); err != nil { return err } } diff --git a/std/recursion/plonk/verifier_test.go b/std/recursion/plonk/verifier_test.go index 243a0ffb1f..1c4dd49717 100644 --- a/std/recursion/plonk/verifier_test.go +++ b/std/recursion/plonk/verifier_test.go @@ -62,6 +62,8 @@ type OuterCircuit[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2Ele Proof Proof[S, G1El, G2El] VerifyingKey VerifyingKey[S, G1El, G2El] InnerWitness Witness[S] + + target *big.Int // TODO: remove later } func (c *OuterCircuit[S, G1El, G2El, GtEl]) Define(api frontend.API) error { @@ -73,7 +75,12 @@ func (c *OuterCircuit[S, G1El, G2El, GtEl]) Define(api frontend.API) error { if err != nil { return fmt.Errorf("get pairing: %w", err) } - verifier := NewVerifier(api, curve, pairing) + // TODO: should do automatically but we need modulus. Hopefully Arithmetization returns it. + fsHhash, err := recursion.NewHash(api, c.target) + if err != nil { + return fmt.Errorf("get hash: %w", err) + } + verifier := NewVerifier(api, curve, pairing, fsHhash) err = verifier.AssertProof(c.VerifyingKey, c.Proof, c.InnerWitness) return err } @@ -92,12 +99,16 @@ func TestBLS12InBW6(t *testing.T) { 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), + target: ecc.BLS12_377.ScalarField(), } outerAssignment := &OuterCircuit[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ InnerWitness: circuitWitness, Proof: circuitProof, VerifyingKey: circuitVk, + target: ecc.BLS12_377.ScalarField(), } - assert.CheckCircuit(outerCircuit, test.WithValidAssignment(outerAssignment), test.WithCurves(ecc.BW6_761)) + assert.CheckCircuit(outerCircuit, test.WithValidAssignment(outerAssignment), test.WithCurves(ecc.BW6_761), + test.NoFuzzing(), test.NoSerializationChecks(), test.NoSolidityChecks()) }