From c9f99784d6121eda73cc13e3a6ae6e2774ec7c66 Mon Sep 17 00:00:00 2001 From: Lucas Menendez Date: Thu, 20 Feb 2025 14:37:28 +0100 Subject: [PATCH 1/4] move vote verifier and aggregator circuit to plonk (inner aggregator proofs verification fails) --- circuits/aggregator/aggregator.go | 43 +++++++++---------- circuits/aggregator/helpers.go | 40 +++++++++-------- circuits/dummy/dummy_helpers.go | 23 ++++++---- circuits/test/aggregator/aggregator_inputs.go | 35 +++++++++------ circuits/test/aggregator/aggregator_test.go | 6 +-- .../test/voteverifier/vote_verifier_test.go | 2 +- circuits/voters_hashes.go | 5 ++- go.mod | 4 +- go.sum | 8 ++-- 9 files changed, 93 insertions(+), 73 deletions(-) diff --git a/circuits/aggregator/aggregator.go b/circuits/aggregator/aggregator.go index 4cd31bb9..085194f9 100644 --- a/circuits/aggregator/aggregator.go +++ b/circuits/aggregator/aggregator.go @@ -31,7 +31,7 @@ import ( "github.com/consensys/gnark/std/algebra/native/sw_bls12377" "github.com/consensys/gnark/std/math/bits" "github.com/consensys/gnark/std/math/emulated" - "github.com/consensys/gnark/std/recursion/groth16" + stdplonk "github.com/consensys/gnark/std/recursion/plonk" "github.com/vocdoni/vocdoni-z-sandbox/circuits" ) @@ -47,9 +47,10 @@ type AggregatorCircuit struct { // Inner proofs (from VerifyVoteCircuit) and verification keys (base is the // real vk and dummy is used for no valid proofs in the scenario where there // are less valid votes than MaxVotes) - Proofs [circuits.VotesPerBatch]groth16.Proof[sw_bls12377.G1Affine, sw_bls12377.G2Affine] - BaseVerificationKey groth16.VerifyingKey[sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT] `gnark:"-"` - DummyVerificationKey groth16.VerifyingKey[sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT] `gnark:"-"` + Proofs [circuits.VotesPerBatch]stdplonk.Proof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine] + BaseVerificationKey stdplonk.BaseVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine] `gnark:"-"` + VerificationKey stdplonk.CircuitVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine] `gnark:"-"` + DummyVerificationKey stdplonk.CircuitVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine] `gnark:"-"` } // checkProofs circuit method verifies each voter proof with the provided @@ -60,34 +61,30 @@ type AggregatorCircuit struct { // but it assert that all the proofs are valid. func (c AggregatorCircuit) checkProofs(api frontend.API, hashes circuits.VotersHashes) { // initialize the verifier of the BLS12-377 curve - verifier, err := groth16.NewVerifier[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT](api) + verifier, err := stdplonk.NewVerifier[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT](api) if err != nil { circuits.FrontendError(api, "failed to create BLS12-377 verifier", err) } - // verify each proof with the provided public inputs and the fixed - // verification key - validProofs := bits.ToBinary(api, c.ValidVotes) + // decode the valid proofs indicators from the binary representation + // take only the first len(c.Proofs) bits to avoid length mismatch + validProofs := bits.ToBinary(api, c.ValidVotes)[:len(c.Proofs)] + // calculate the witness for each voter + witnesses := []stdplonk.Witness[sw_bls12377.ScalarField]{} for i := 0; i < len(c.Proofs); i++ { - // switch the verification key between the base and the dummy one if - // the proof is valid or not - vk, err := verifier.SwitchVerificationKey(validProofs[i], - []groth16.VerifyingKey[sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{ - c.DummyVerificationKey, - c.BaseVerificationKey, - }, - ) - if err != nil { - circuits.FrontendError(api, "failed to switch verification key", err) - } // calculate the witness for the i-th voter calculatedWitness, err := hashes.ToWitnessBLS12377(api, i, validProofs[i]) if err != nil { circuits.FrontendError(api, "failed to calculate witness", err) } - // verify the proof - if err := verifier.AssertProof(vk, c.Proofs[i], calculatedWitness); err != nil { - circuits.FrontendError(api, "failed to verify proof", err) - } + witnesses = append(witnesses, calculatedWitness) + } + // verify all the proofs + if err := verifier.AssertDifferentProofs(c.BaseVerificationKey, + []stdplonk.CircuitVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine]{ + c.DummyVerificationKey, c.VerificationKey, + }, validProofs, c.Proofs[:], witnesses, + ); err != nil { + circuits.FrontendError(api, "failed to verify proofs", err) } } diff --git a/circuits/aggregator/helpers.go b/circuits/aggregator/helpers.go index 3a011a1b..81f4e731 100644 --- a/circuits/aggregator/helpers.go +++ b/circuits/aggregator/helpers.go @@ -8,7 +8,7 @@ import ( "github.com/consensys/gnark/std/algebra/emulated/sw_bn254" "github.com/consensys/gnark/std/algebra/native/sw_bls12377" "github.com/consensys/gnark/std/math/emulated" - stdgroth16 "github.com/consensys/gnark/std/recursion/groth16" + stdplonk "github.com/consensys/gnark/std/recursion/plonk" "github.com/vocdoni/vocdoni-z-sandbox/circuits" "github.com/vocdoni/vocdoni-z-sandbox/circuits/dummy" ) @@ -33,36 +33,42 @@ func EncodeProofsSelector(nValidProofs int) *big.Int { func RecursiveDummy(main constraint.ConstraintSystem, persist bool) ( constraint.ConstraintSystem, - stdgroth16.VerifyingKey[sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT], - stdgroth16.Proof[sw_bls12377.G1Affine, sw_bls12377.G2Affine], - stdgroth16.Witness[sw_bls12377.ScalarField], + stdplonk.BaseVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine], + stdplonk.CircuitVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine], + stdplonk.Proof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine], + stdplonk.Witness[sw_bls12377.ScalarField], error, ) { - nilVk := stdgroth16.VerifyingKey[sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{} - nilProof := stdgroth16.Proof[sw_bls12377.G1Affine, sw_bls12377.G2Affine]{} - nilWitness := stdgroth16.Witness[sw_bls12377.ScalarField]{} + nilBaseVk := stdplonk.BaseVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine]{} + nilVk := stdplonk.CircuitVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine]{} + nilProof := stdplonk.Proof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine]{} + nilWitness := stdplonk.Witness[sw_bls12377.ScalarField]{} dummyCCS, pubWitness, proof, vk, err := dummy.Prove( dummy.Placeholder(main), dummy.Assignment(1), circuits.AggregatorCurve.ScalarField(), circuits.VoteVerifierCurve.ScalarField(), persist) if err != nil { - return nil, nilVk, nilProof, nilWitness, err + return nil, nilBaseVk, nilVk, nilProof, nilWitness, err } // set fixed dummy vk in the placeholders - dummyVk, err := stdgroth16.ValueOfVerifyingKeyFixed[sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT](vk) + baseDummyVk, err := stdplonk.ValueOfBaseVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](vk) if err != nil { - return nil, nilVk, nilProof, nilWitness, fmt.Errorf("fix dummy vk error: %w", err) + return nil, nilBaseVk, nilVk, nilProof, nilWitness, fmt.Errorf("fix base dummy vk error: %w", err) + } + dummyVk, err := stdplonk.ValueOfCircuitVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine](vk) + if err != nil { + return nil, nilBaseVk, nilVk, nilProof, nilWitness, fmt.Errorf("fix dummy vk error: %w", err) } // parse dummy proof and witness - dummyProof, err := stdgroth16.ValueOfProof[sw_bls12377.G1Affine, sw_bls12377.G2Affine](proof) + dummyProof, err := stdplonk.ValueOfProof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](proof) if err != nil { - return nil, nilVk, nilProof, nilWitness, fmt.Errorf("dummy proof value error: %w", err) + return nil, nilBaseVk, nilVk, nilProof, nilWitness, fmt.Errorf("dummy proof value error: %w", err) } - dummyWitness, err := stdgroth16.ValueOfWitness[sw_bls12377.ScalarField](pubWitness) + dummyWitness, err := stdplonk.ValueOfWitness[sw_bls12377.ScalarField](pubWitness) if err != nil { - return nil, nilVk, nilProof, nilWitness, fmt.Errorf("dummy witness value error: %w", err) + return nil, nilBaseVk, nilVk, nilProof, nilWitness, fmt.Errorf("dummy witness value error: %w", err) } - return dummyCCS, dummyVk, dummyProof, dummyWitness, nil + return dummyCCS, baseDummyVk, dummyVk, dummyProof, dummyWitness, nil } // FillWithDummyFixed function fills the placeholder and the assignments @@ -73,7 +79,7 @@ func RecursiveDummy(main constraint.ConstraintSystem, persist bool) ( func FillWithDummyFixed(placeholder, assignments AggregatorCircuit, main constraint.ConstraintSystem, fromIdx int, persist bool) ( AggregatorCircuit, AggregatorCircuit, error, ) { - dummyCCS, dummyVk, dummyProof, _, err := RecursiveDummy(main, persist) + dummyCCS, _, dummyVk, dummyProof, _, err := RecursiveDummy(main, persist) if err != nil { return AggregatorCircuit{}, AggregatorCircuit{}, err } @@ -83,7 +89,7 @@ func FillWithDummyFixed(placeholder, assignments AggregatorCircuit, main constra dummyValue := emulated.ValueOf[sw_bn254.ScalarField](0) // fill placeholders and assignments dummy values for i := range assignments.Proofs { - placeholder.Proofs[i] = stdgroth16.PlaceholderProof[sw_bls12377.G1Affine, sw_bls12377.G2Affine](dummyCCS) + placeholder.Proofs[i] = stdplonk.PlaceholderProof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](dummyCCS) if i >= fromIdx { assignments.Votes[i].Nullifier = dummyValue assignments.Votes[i].Commitment = dummyValue diff --git a/circuits/dummy/dummy_helpers.go b/circuits/dummy/dummy_helpers.go index 63da954d..e50c20ab 100644 --- a/circuits/dummy/dummy_helpers.go +++ b/circuits/dummy/dummy_helpers.go @@ -4,15 +4,16 @@ import ( "fmt" "math/big" - "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/backend/plonk" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/r1cs" - stdgroth16 "github.com/consensys/gnark/std/recursion/groth16" + "github.com/consensys/gnark/frontend/cs/scs" + stdplonk "github.com/consensys/gnark/std/recursion/plonk" + "github.com/consensys/gnark/test/unsafekzg" ) -func Prove(placeholder, assignment frontend.Circuit, outer *big.Int, field *big.Int, persist bool) (constraint.ConstraintSystem, witness.Witness, groth16.Proof, groth16.VerifyingKey, error) { +func Prove(placeholder, assignment frontend.Circuit, outer *big.Int, field *big.Int, persist bool) (constraint.ConstraintSystem, witness.Witness, plonk.Proof, plonk.VerifyingKey, error) { ccs, pk, vk, err := CompileAndSetup(placeholder, field) if err != nil { return nil, nil, nil, nil, fmt.Errorf("init error: %w", err) @@ -21,7 +22,7 @@ func Prove(placeholder, assignment frontend.Circuit, outer *big.Int, field *big. if err != nil { return nil, nil, nil, nil, fmt.Errorf("full witness error: %w", err) } - proof, err := groth16.Prove(ccs, pk, fullWitness, stdgroth16.GetNativeProverOptions(outer, field)) + proof, err := plonk.Prove(ccs, pk, fullWitness, stdplonk.GetNativeProverOptions(outer, field)) if err != nil { return nil, nil, nil, nil, fmt.Errorf("proof error: %w", err) } @@ -29,7 +30,7 @@ func Prove(placeholder, assignment frontend.Circuit, outer *big.Int, field *big. if err != nil { return nil, nil, nil, nil, fmt.Errorf("pub witness error: %w", err) } - if err = groth16.Verify(proof, vk, publicWitness, stdgroth16.GetNativeVerifierOptions(outer, field)); err != nil { + if err = plonk.Verify(proof, vk, publicWitness, stdplonk.GetNativeVerifierOptions(outer, field)); err != nil { return nil, nil, nil, nil, fmt.Errorf("verify error: %w", err) } /* @@ -53,12 +54,16 @@ func Prove(placeholder, assignment frontend.Circuit, outer *big.Int, field *big. return ccs, publicWitness, proof, vk, nil } -func CompileAndSetup(placeholder frontend.Circuit, field *big.Int) (constraint.ConstraintSystem, groth16.ProvingKey, groth16.VerifyingKey, error) { - ccs, err := frontend.Compile(field, r1cs.NewBuilder, placeholder) +func CompileAndSetup(placeholder frontend.Circuit, field *big.Int) (constraint.ConstraintSystem, plonk.ProvingKey, plonk.VerifyingKey, error) { + ccs, err := frontend.Compile(field, scs.NewBuilder, placeholder) if err != nil { return nil, nil, nil, fmt.Errorf("compile error: %w", err) } - pk, vk, err := groth16.Setup(ccs) + srs, srsLagrange, err := unsafekzg.NewSRS(ccs) + if err != nil { + return nil, nil, nil, fmt.Errorf("srs error: %w", err) + } + pk, vk, err := plonk.Setup(ccs, srs, srsLagrange) if err != nil { return nil, nil, nil, fmt.Errorf("setup error: %w", err) } diff --git a/circuits/test/aggregator/aggregator_inputs.go b/circuits/test/aggregator/aggregator_inputs.go index 7fe63c27..2da05c47 100644 --- a/circuits/test/aggregator/aggregator_inputs.go +++ b/circuits/test/aggregator/aggregator_inputs.go @@ -4,13 +4,14 @@ import ( "fmt" "math/big" - "github.com/consensys/gnark/backend/groth16" + "github.com/consensys/gnark/backend/plonk" "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/std/algebra/emulated/sw_bn254" "github.com/consensys/gnark/std/algebra/native/sw_bls12377" "github.com/consensys/gnark/std/math/emulated" - stdgroth16 "github.com/consensys/gnark/std/recursion/groth16" + stdplonk "github.com/consensys/gnark/std/recursion/plonk" + "github.com/consensys/gnark/test/unsafekzg" "github.com/iden3/go-iden3-crypto/mimc7" "github.com/vocdoni/arbo" "github.com/vocdoni/vocdoni-z-sandbox/circuits" @@ -180,11 +181,15 @@ func AggregatorInputsForTest(processId []byte, nValidVoters int, persist bool) ( return AggregatorTestResults{}, aggregator.AggregatorCircuit{}, aggregator.AggregatorCircuit{}, fmt.Errorf("voteverifier inputs: %w", err) } // compile vote verifier circuit - vvCCS, err := frontend.Compile(circuits.VoteVerifierCurve.ScalarField(), r1cs.NewBuilder, &vvPlaceholder) + vvCCS, err := frontend.Compile(circuits.VoteVerifierCurve.ScalarField(), scs.NewBuilder, &vvPlaceholder) if err != nil { return AggregatorTestResults{}, aggregator.AggregatorCircuit{}, aggregator.AggregatorCircuit{}, err } - vvPk, vvVk, err := groth16.Setup(vvCCS) + c, l, err := unsafekzg.NewSRS(vvCCS) + if err != nil { + return AggregatorTestResults{}, aggregator.AggregatorCircuit{}, aggregator.AggregatorCircuit{}, err + } + vvPk, vvVk, err := plonk.Setup(vvCCS, c, l) if err != nil { return AggregatorTestResults{}, aggregator.AggregatorCircuit{}, aggregator.AggregatorCircuit{}, err } @@ -200,7 +205,7 @@ func AggregatorInputsForTest(processId []byte, nValidVoters int, persist bool) ( } */ // generate voters proofs - proofs := [circuits.VotesPerBatch]stdgroth16.Proof[sw_bls12377.G1Affine, sw_bls12377.G2Affine]{} + proofs := [circuits.VotesPerBatch]stdplonk.Proof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine]{} for i := range vvAssigments { // parse the witness to the circuit fullWitness, err := frontend.NewWitness(&vvAssigments[i], circuits.VoteVerifierCurve.ScalarField()) @@ -208,14 +213,14 @@ func AggregatorInputsForTest(processId []byte, nValidVoters int, persist bool) ( return AggregatorTestResults{}, aggregator.AggregatorCircuit{}, aggregator.AggregatorCircuit{}, err } // generate the proof - proof, err := groth16.Prove(vvCCS, vvPk, fullWitness, stdgroth16.GetNativeProverOptions( + proof, err := plonk.Prove(vvCCS, vvPk, fullWitness, stdplonk.GetNativeProverOptions( circuits.AggregatorCurve.ScalarField(), circuits.VoteVerifierCurve.ScalarField())) if err != nil { return AggregatorTestResults{}, aggregator.AggregatorCircuit{}, aggregator.AggregatorCircuit{}, fmt.Errorf("err proving voteverifier circuit %d: %w", i, err) } // convert the proof to the circuit proof type - proofs[i], err = stdgroth16.ValueOfProof[sw_bls12377.G1Affine, sw_bls12377.G2Affine](proof) + proofs[i], err = stdplonk.ValueOfProof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](proof) if err != nil { return AggregatorTestResults{}, aggregator.AggregatorCircuit{}, aggregator.AggregatorCircuit{}, err } @@ -224,7 +229,8 @@ func AggregatorInputsForTest(processId []byte, nValidVoters int, persist bool) ( if err != nil { return AggregatorTestResults{}, aggregator.AggregatorCircuit{}, aggregator.AggregatorCircuit{}, err } - err = groth16.Verify(proof, vvVk, publicWitness, stdgroth16.GetNativeVerifierOptions( + // verify the proof before continue + err = plonk.Verify(proof, vvVk, publicWitness, stdplonk.GetNativeVerifierOptions( circuits.AggregatorCurve.ScalarField(), circuits.VoteVerifierCurve.ScalarField())) if err != nil { @@ -295,14 +301,19 @@ func AggregatorInputsForTest(processId []byte, nValidVoters int, persist bool) ( } } // fix the vote verifier verification key - fixedVk, err := stdgroth16.ValueOfVerifyingKeyFixed[sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT](vvVk) + fixedVk, err := stdplonk.ValueOfCircuitVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine](vvVk) + if err != nil { + return AggregatorTestResults{}, aggregator.AggregatorCircuit{}, aggregator.AggregatorCircuit{}, err + } + baseVk, err := stdplonk.ValueOfBaseVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine](vvVk) if err != nil { return AggregatorTestResults{}, aggregator.AggregatorCircuit{}, aggregator.AggregatorCircuit{}, err } // create final placeholder finalPlaceholder := aggregator.AggregatorCircuit{ - Proofs: [circuits.VotesPerBatch]stdgroth16.Proof[sw_bls12377.G1Affine, sw_bls12377.G2Affine]{}, - BaseVerificationKey: fixedVk, + Proofs: [circuits.VotesPerBatch]stdplonk.Proof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine]{}, + VerificationKey: fixedVk, + BaseVerificationKey: baseVk, } // fill placeholder and witness with dummy circuits finalPlaceholder, finalAssigments, err = aggregator.FillWithDummyFixed(finalPlaceholder, finalAssigments, vvCCS, nValidVoters, persist) diff --git a/circuits/test/aggregator/aggregator_test.go b/circuits/test/aggregator/aggregator_test.go index 1e07f70c..6b9ad3f3 100644 --- a/circuits/test/aggregator/aggregator_test.go +++ b/circuits/test/aggregator/aggregator_test.go @@ -6,7 +6,7 @@ import ( "time" "github.com/consensys/gnark/backend" - stdgroth16 "github.com/consensys/gnark/std/recursion/groth16" + stdplonk "github.com/consensys/gnark/std/recursion/plonk" "github.com/consensys/gnark/test" qt "github.com/frankban/quicktest" "github.com/vocdoni/vocdoni-z-sandbox/circuits" @@ -28,8 +28,8 @@ func TestAggregatorCircuit(t *testing.T) { now = time.Now() assert := test.NewAssert(t) assert.SolvingSucceeded(&placeholder, &assignments, - test.WithCurves(circuits.AggregatorCurve), test.WithBackends(backend.GROTH16), - test.WithProverOpts(stdgroth16.GetNativeProverOptions( + test.WithCurves(circuits.AggregatorCurve), test.WithBackends(backend.PLONK), + test.WithProverOpts(stdplonk.GetNativeProverOptions( circuits.StateTransitionCurve.ScalarField(), circuits.AggregatorCurve.ScalarField()))) c.Logf("proving tooks %s", time.Since(now).String()) diff --git a/circuits/test/voteverifier/vote_verifier_test.go b/circuits/test/voteverifier/vote_verifier_test.go index ec14507f..fd080696 100644 --- a/circuits/test/voteverifier/vote_verifier_test.go +++ b/circuits/test/voteverifier/vote_verifier_test.go @@ -31,7 +31,7 @@ func TestVerifySingleVoteCircuit(t *testing.T) { now := time.Now() assert.SolvingSucceeded(&placeholder, &assignments[0], test.WithCurves(ecc.BLS12_377), - test.WithBackends(backend.GROTH16)) + test.WithBackends(backend.PLONK)) fmt.Println("proving tooks", time.Since(now)) } diff --git a/circuits/voters_hashes.go b/circuits/voters_hashes.go index b52e553d..b37cf3d2 100644 --- a/circuits/voters_hashes.go +++ b/circuits/voters_hashes.go @@ -7,6 +7,7 @@ import ( "github.com/consensys/gnark/std/algebra/native/sw_bls12377" "github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/std/recursion/groth16" + "github.com/consensys/gnark/std/recursion/plonk" "github.com/vocdoni/gnark-crypto-primitives/emulated/bn254/twistededwards/mimc7" ) @@ -74,7 +75,7 @@ func (vh VotersHashes) AssertSumIsEqual(api frontend.API, expected emulated.Elem // ], // } func (vh VotersHashes) ToWitnessBLS12377(api frontend.API, idx int, valid frontend.Variable) ( - groth16.Witness[sw_bls12377.ScalarField], error, + plonk.Witness[sw_bls12377.ScalarField], error, ) { field, err := emulated.NewField[sw_bn254.ScalarField](api) if err != nil { @@ -92,7 +93,7 @@ func (vh VotersHashes) ToWitnessBLS12377(api frontend.API, idx int, valid fronte Limbs: []frontend.Variable{finalLimb, 0, 0, 0}, }) } - return groth16.Witness[sw_bls12377.ScalarField]{Public: splitedHash}, nil + return plonk.Witness[sw_bls12377.ScalarField]{Public: splitedHash}, nil } // ToWitnessBW6761 method calculates the witness using the current diff --git a/go.mod b/go.mod index e394d559..a9f56be7 100644 --- a/go.mod +++ b/go.mod @@ -2,11 +2,11 @@ module github.com/vocdoni/vocdoni-z-sandbox go 1.23.2 -replace github.com/consensys/gnark => github.com/lucasmenendez/gnark v0.5.2-0.20250131151401-59fb979789bd +replace github.com/consensys/gnark => github.com/lucasmenendez/gnark v0.5.2-0.20250219083101-95ae8b00f663 require ( github.com/consensys/gnark v0.11.1-0.20241210204654-a1e66c1d6b4d - github.com/consensys/gnark-crypto v0.16.0 + github.com/consensys/gnark-crypto v0.16.1-0.20250205153847-10a243d332ca github.com/ethereum/go-ethereum v1.14.12 github.com/frankban/quicktest v1.14.6 github.com/fxamacker/cbor/v2 v2.7.0 diff --git a/go.sum b/go.sum index 7a470825..38d58851 100644 --- a/go.sum +++ b/go.sum @@ -119,8 +119,8 @@ github.com/compose-spec/compose-go/v2 v2.1.3 h1:bD67uqLuL/XgkAK6ir3xZvNLFPxPScEi github.com/compose-spec/compose-go/v2 v2.1.3/go.mod h1:lFN0DrMxIncJGYAXTfWuajfwj5haBJqrBkarHcnjJKc= github.com/consensys/bavard v0.1.29 h1:fobxIYksIQ+ZSrTJUuQgu+HIJwclrAPcdXqd7H2hh1k= github.com/consensys/bavard v0.1.29/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs= -github.com/consensys/gnark-crypto v0.16.0 h1:8Dl4eYmUWK9WmlP1Bj6je688gBRJCJbT8Mw4KoTAawo= -github.com/consensys/gnark-crypto v0.16.0/go.mod h1:Ke3j06ndtPTVvo++PhGNgvm+lgpLvzbcE2MqljY7diU= +github.com/consensys/gnark-crypto v0.16.1-0.20250205153847-10a243d332ca h1:u6iXwMBfbXODF+hDSwKSTBg6yfD3+eMX6o3PILAK474= +github.com/consensys/gnark-crypto v0.16.1-0.20250205153847-10a243d332ca/go.mod h1:Ke3j06ndtPTVvo++PhGNgvm+lgpLvzbcE2MqljY7diU= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro= @@ -429,8 +429,8 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+ github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4= github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= github.com/lib/pq v0.0.0-20150723085316-0dad96c0b94f/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lucasmenendez/gnark v0.5.2-0.20250131151401-59fb979789bd h1:olPPMAQ8VakgWhWcEQxmYaiJCjJqJMpZ2AoqTNfxLDM= -github.com/lucasmenendez/gnark v0.5.2-0.20250131151401-59fb979789bd/go.mod h1:WDvuIQ8qrRvWT9NhTrib84WeLVBSGhSTrbQBXs1yR5w= +github.com/lucasmenendez/gnark v0.5.2-0.20250219083101-95ae8b00f663 h1:h7o6ClcXaeT2gih18M2WbY7DyBSDIxosMi+FEFTPu5g= +github.com/lucasmenendez/gnark v0.5.2-0.20250219083101-95ae8b00f663/go.mod h1:fJRBRhr7M6+l7vp/qjXqxetnKmoEuDH4ErcmtlhtIzA= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.5.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= From 3a2b958d8e56d169b3abd775d29b4c1f8eb145c2 Mon Sep 17 00:00:00 2001 From: Lucas Menendez Date: Fri, 21 Feb 2025 13:25:20 +0100 Subject: [PATCH 2/4] explicit implementation of vk switching --- circuits/aggregator/aggregator.go | 38 +++++++++++++++++-------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/circuits/aggregator/aggregator.go b/circuits/aggregator/aggregator.go index 085194f9..0b9cb5dd 100644 --- a/circuits/aggregator/aggregator.go +++ b/circuits/aggregator/aggregator.go @@ -31,7 +31,7 @@ import ( "github.com/consensys/gnark/std/algebra/native/sw_bls12377" "github.com/consensys/gnark/std/math/bits" "github.com/consensys/gnark/std/math/emulated" - stdplonk "github.com/consensys/gnark/std/recursion/plonk" + "github.com/consensys/gnark/std/recursion/plonk" "github.com/vocdoni/vocdoni-z-sandbox/circuits" ) @@ -47,10 +47,10 @@ type AggregatorCircuit struct { // Inner proofs (from VerifyVoteCircuit) and verification keys (base is the // real vk and dummy is used for no valid proofs in the scenario where there // are less valid votes than MaxVotes) - Proofs [circuits.VotesPerBatch]stdplonk.Proof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine] - BaseVerificationKey stdplonk.BaseVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine] `gnark:"-"` - VerificationKey stdplonk.CircuitVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine] `gnark:"-"` - DummyVerificationKey stdplonk.CircuitVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine] `gnark:"-"` + Proofs [circuits.VotesPerBatch]plonk.Proof[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine] + BaseVerificationKey plonk.BaseVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine] `gnark:"-"` + VerificationKey plonk.CircuitVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine] `gnark:"-"` + DummyVerificationKey plonk.CircuitVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine] `gnark:"-"` } // checkProofs circuit method verifies each voter proof with the provided @@ -61,30 +61,34 @@ type AggregatorCircuit struct { // but it assert that all the proofs are valid. func (c AggregatorCircuit) checkProofs(api frontend.API, hashes circuits.VotersHashes) { // initialize the verifier of the BLS12-377 curve - verifier, err := stdplonk.NewVerifier[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT](api) + verifier, err := plonk.NewVerifier[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT](api) if err != nil { circuits.FrontendError(api, "failed to create BLS12-377 verifier", err) } // decode the valid proofs indicators from the binary representation // take only the first len(c.Proofs) bits to avoid length mismatch validProofs := bits.ToBinary(api, c.ValidVotes)[:len(c.Proofs)] - // calculate the witness for each voter - witnesses := []stdplonk.Witness[sw_bls12377.ScalarField]{} + // calculate the witness for each voter and verify each proof with it for i := 0; i < len(c.Proofs); i++ { + api.Println("Checking proof", i) + api.Println("Valid proof?", validProofs[i]) // calculate the witness for the i-th voter calculatedWitness, err := hashes.ToWitnessBLS12377(api, i, validProofs[i]) if err != nil { circuits.FrontendError(api, "failed to calculate witness", err) } - witnesses = append(witnesses, calculatedWitness) - } - // verify all the proofs - if err := verifier.AssertDifferentProofs(c.BaseVerificationKey, - []stdplonk.CircuitVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine]{ - c.DummyVerificationKey, c.VerificationKey, - }, validProofs, c.Proofs[:], witnesses, - ); err != nil { - circuits.FrontendError(api, "failed to verify proofs", err) + // switch the verification key to the dummy one if the proof is not valid + vk, err := verifier.SwitchVerificationKey(c.BaseVerificationKey, validProofs[i], + []plonk.CircuitVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine]{ + c.DummyVerificationKey, c.VerificationKey, + }) + if err != nil { + circuits.FrontendError(api, "failed to switch verification key", err) + } + // verify the proof with the calculated witness and the verification key + if err := verifier.AssertProof(vk, c.Proofs[i], calculatedWitness); err != nil { + circuits.FrontendError(api, "failed to verify proof", err) + } } } From fcab1e2b34c383565124269b2157d90aa47a949c Mon Sep 17 00:00:00 2001 From: Lucas Menendez Date: Mon, 24 Feb 2025 09:58:32 +0100 Subject: [PATCH 3/4] use same kzg srs for both circuits, voteverifier and dummy --- circuits/aggregator/helpers.go | 9 +++-- circuits/dummy/dummy_helpers.go | 12 ++---- circuits/dummy/dummy_test.go | 38 ++++++++++++++++++- circuits/test/aggregator/aggregator_inputs.go | 11 +++--- 4 files changed, 51 insertions(+), 19 deletions(-) diff --git a/circuits/aggregator/helpers.go b/circuits/aggregator/helpers.go index 81f4e731..20774401 100644 --- a/circuits/aggregator/helpers.go +++ b/circuits/aggregator/helpers.go @@ -4,6 +4,7 @@ import ( "fmt" "math/big" + "github.com/consensys/gnark-crypto/kzg" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/std/algebra/emulated/sw_bn254" "github.com/consensys/gnark/std/algebra/native/sw_bls12377" @@ -31,7 +32,7 @@ func EncodeProofsSelector(nValidProofs int) *big.Int { return maxNum.Sub(maxNum, big.NewInt(1)) } -func RecursiveDummy(main constraint.ConstraintSystem, persist bool) ( +func RecursiveDummy(main constraint.ConstraintSystem, persist bool, srs, srsLagrange kzg.SRS) ( constraint.ConstraintSystem, stdplonk.BaseVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine], stdplonk.CircuitVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine], @@ -46,7 +47,7 @@ func RecursiveDummy(main constraint.ConstraintSystem, persist bool) ( dummyCCS, pubWitness, proof, vk, err := dummy.Prove( dummy.Placeholder(main), dummy.Assignment(1), - circuits.AggregatorCurve.ScalarField(), circuits.VoteVerifierCurve.ScalarField(), persist) + circuits.AggregatorCurve.ScalarField(), circuits.VoteVerifierCurve.ScalarField(), persist, srs, srsLagrange) if err != nil { return nil, nilBaseVk, nilVk, nilProof, nilWitness, err } @@ -76,10 +77,10 @@ func RecursiveDummy(main constraint.ConstraintSystem, persist bool) ( // constraint.ConstraintSystem provided. It starts to fill from the index // provided and fixes the dummy verification key. Returns an error if // something fails. -func FillWithDummyFixed(placeholder, assignments AggregatorCircuit, main constraint.ConstraintSystem, fromIdx int, persist bool) ( +func FillWithDummyFixed(placeholder, assignments AggregatorCircuit, main constraint.ConstraintSystem, fromIdx int, persist bool, srs, srsLagrange kzg.SRS) ( AggregatorCircuit, AggregatorCircuit, error, ) { - dummyCCS, _, dummyVk, dummyProof, _, err := RecursiveDummy(main, persist) + dummyCCS, _, dummyVk, dummyProof, _, err := RecursiveDummy(main, persist, srs, srsLagrange) if err != nil { return AggregatorCircuit{}, AggregatorCircuit{}, err } diff --git a/circuits/dummy/dummy_helpers.go b/circuits/dummy/dummy_helpers.go index e50c20ab..3248224c 100644 --- a/circuits/dummy/dummy_helpers.go +++ b/circuits/dummy/dummy_helpers.go @@ -4,17 +4,17 @@ import ( "fmt" "math/big" + "github.com/consensys/gnark-crypto/kzg" "github.com/consensys/gnark/backend/plonk" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/scs" stdplonk "github.com/consensys/gnark/std/recursion/plonk" - "github.com/consensys/gnark/test/unsafekzg" ) -func Prove(placeholder, assignment frontend.Circuit, outer *big.Int, field *big.Int, persist bool) (constraint.ConstraintSystem, witness.Witness, plonk.Proof, plonk.VerifyingKey, error) { - ccs, pk, vk, err := CompileAndSetup(placeholder, field) +func Prove(placeholder, assignment frontend.Circuit, outer *big.Int, field *big.Int, persist bool, srs, srsLagrange kzg.SRS) (constraint.ConstraintSystem, witness.Witness, plonk.Proof, plonk.VerifyingKey, error) { + ccs, pk, vk, err := CompileAndSetup(placeholder, field, srs, srsLagrange) if err != nil { return nil, nil, nil, nil, fmt.Errorf("init error: %w", err) } @@ -54,15 +54,11 @@ func Prove(placeholder, assignment frontend.Circuit, outer *big.Int, field *big. return ccs, publicWitness, proof, vk, nil } -func CompileAndSetup(placeholder frontend.Circuit, field *big.Int) (constraint.ConstraintSystem, plonk.ProvingKey, plonk.VerifyingKey, error) { +func CompileAndSetup(placeholder frontend.Circuit, field *big.Int, srs, srsLagrange kzg.SRS) (constraint.ConstraintSystem, plonk.ProvingKey, plonk.VerifyingKey, error) { ccs, err := frontend.Compile(field, scs.NewBuilder, placeholder) if err != nil { return nil, nil, nil, fmt.Errorf("compile error: %w", err) } - srs, srsLagrange, err := unsafekzg.NewSRS(ccs) - if err != nil { - return nil, nil, nil, fmt.Errorf("srs error: %w", err) - } pk, vk, err := plonk.Setup(ccs, srs, srsLagrange) if err != nil { return nil, nil, nil, fmt.Errorf("setup error: %w", err) diff --git a/circuits/dummy/dummy_test.go b/circuits/dummy/dummy_test.go index 385debd5..b826d549 100644 --- a/circuits/dummy/dummy_test.go +++ b/circuits/dummy/dummy_test.go @@ -3,17 +3,21 @@ package dummy import ( "testing" + plonk "github.com/consensys/gnark/backend/plonk" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/cs/r1cs" + "github.com/consensys/gnark/frontend/cs/scs" "github.com/consensys/gnark/std/algebra/native/sw_bls12377" stdgroth16 "github.com/consensys/gnark/std/recursion/groth16" + stdplonk "github.com/consensys/gnark/std/recursion/plonk" + "github.com/consensys/gnark/test/unsafekzg" qt "github.com/frankban/quicktest" "github.com/vocdoni/vocdoni-z-sandbox/circuits" ballottest "github.com/vocdoni/vocdoni-z-sandbox/circuits/test/ballotproof" "github.com/vocdoni/vocdoni-z-sandbox/circuits/voteverifier" ) -func TestSameCircuitsInfo(t *testing.T) { +func TestSameCircuitsInfoGroth16(t *testing.T) { c := qt.New(t) // generate inner circuit placeholders circomPlaceholder, err := circuits.Circom2GnarkPlaceholder(ballottest.TestCircomVerificationKey) @@ -41,3 +45,35 @@ func TestSameCircuitsInfo(t *testing.T) { c.Assert(dummyVk.PublicAndCommitmentCommitted, qt.ContentEquals, mainVk.PublicAndCommitmentCommitted, qt.Commentf("PublicAndCommitmentCommitted %v vs %v", dummyVk.PublicAndCommitmentCommitted, mainVk.PublicAndCommitmentCommitted)) } + +func TestSameCircuitsInfoPlonk(t *testing.T) { + c := qt.New(t) + // generate inner circuit placeholders + circomPlaceholder, err := circuits.Circom2GnarkPlaceholder(ballottest.TestCircomVerificationKey) + c.Assert(err, qt.IsNil) + + // compile the main circuit + mainCCS, err := frontend.Compile(circuits.VoteVerifierCurve.ScalarField(), scs.NewBuilder, &voteverifier.VerifyVoteCircuit{ + CircomProof: circomPlaceholder.Proof, + CircomVerificationKey: circomPlaceholder.Vk, + }) + c.Assert(err, qt.IsNil) + srs, srsLagrange, err := unsafekzg.NewSRS(mainCCS) + c.Assert(err, qt.IsNil) + + _, mainVk, err := plonk.Setup(mainCCS, srs, srsLagrange) + c.Assert(err, qt.IsNil) + mainCircuitVk, err := stdplonk.ValueOfCircuitVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine](mainVk) + c.Assert(err, qt.IsNil) + + dummyCCS, err := frontend.Compile(circuits.VoteVerifierCurve.ScalarField(), scs.NewBuilder, Placeholder(mainCCS)) + c.Assert(err, qt.IsNil) + _, dummyVk, err := plonk.Setup(dummyCCS, srs, srsLagrange) + c.Assert(err, qt.IsNil) + dummyCircuitVk, err := stdplonk.ValueOfCircuitVerifyingKey[sw_bls12377.ScalarField, sw_bls12377.G1Affine](dummyVk) + c.Assert(err, qt.IsNil) + + c.Log("CommitmentConstraintIndexes (main vs. dummy)", len(mainCircuitVk.CommitmentConstraintIndexes), len(dummyCircuitVk.CommitmentConstraintIndexes)) + c.Log("Size (main vs. dummy)", mainCircuitVk.Size, dummyCircuitVk.Size) + c.Log("Qcp (main vs. dummy)", len(mainCircuitVk.Qcp), len(dummyCircuitVk.Qcp)) +} diff --git a/circuits/test/aggregator/aggregator_inputs.go b/circuits/test/aggregator/aggregator_inputs.go index 2da05c47..bdd09c93 100644 --- a/circuits/test/aggregator/aggregator_inputs.go +++ b/circuits/test/aggregator/aggregator_inputs.go @@ -185,11 +185,11 @@ func AggregatorInputsForTest(processId []byte, nValidVoters int, persist bool) ( if err != nil { return AggregatorTestResults{}, aggregator.AggregatorCircuit{}, aggregator.AggregatorCircuit{}, err } - c, l, err := unsafekzg.NewSRS(vvCCS) + srs, srsLagrange, err := unsafekzg.NewSRS(vvCCS) if err != nil { return AggregatorTestResults{}, aggregator.AggregatorCircuit{}, aggregator.AggregatorCircuit{}, err } - vvPk, vvVk, err := plonk.Setup(vvCCS, c, l) + vvPk, vvVk, err := plonk.Setup(vvCCS, srs, srsLagrange) if err != nil { return AggregatorTestResults{}, aggregator.AggregatorCircuit{}, aggregator.AggregatorCircuit{}, err } @@ -316,7 +316,7 @@ func AggregatorInputsForTest(processId []byte, nValidVoters int, persist bool) ( BaseVerificationKey: baseVk, } // fill placeholder and witness with dummy circuits - finalPlaceholder, finalAssigments, err = aggregator.FillWithDummyFixed(finalPlaceholder, finalAssigments, vvCCS, nValidVoters, persist) + finalPlaceholder, finalAssigments, err = aggregator.FillWithDummyFixed(finalPlaceholder, finalAssigments, vvCCS, nValidVoters, persist, srs, srsLagrange) if err != nil { return AggregatorTestResults{}, aggregator.AggregatorCircuit{}, aggregator.AggregatorCircuit{}, err } @@ -334,9 +334,8 @@ func AggregatorInputsForTest(processId []byte, nValidVoters int, persist bool) ( res := AggregatorTestResults{ InputsHash: inputsHash, Process: circuits.Process[*big.Int]{ - ID: vvInputs.ProcessID, - CensusRoot: vvInputs.CensusRoot, - // BallotMode: circuits.BallotMode{}, + ID: vvInputs.ProcessID, + CensusRoot: vvInputs.CensusRoot, EncryptionKey: vvInputs.EncryptionPubKey, }, Votes: votes[:], From 2b2eca61933064aed10f9232f76980a3a24e86ed Mon Sep 17 00:00:00 2001 From: Lucas Menendez Date: Mon, 24 Feb 2025 11:23:37 +0100 Subject: [PATCH 4/4] helper to generate groth16 solidity assets --- circuits/helpers.go | 114 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/circuits/helpers.go b/circuits/helpers.go index dc5d6941..169aaa2a 100644 --- a/circuits/helpers.go +++ b/circuits/helpers.go @@ -1,6 +1,8 @@ package circuits import ( + "bytes" + "encoding/json" "fmt" "log" "math/big" @@ -10,6 +12,7 @@ import ( "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/frontend" + "github.com/consensys/gnark/frontend/cs/r1cs" ) // FrontendError function is an in-circuit function to print an error message @@ -115,3 +118,114 @@ func BoolToBigInt(b bool) *big.Int { } return big.NewInt(0) } + +func Groth16SolidityAssets(name string, c, w frontend.Circuit, field *big.Int) error { + // compile the circuit + ccs, err := frontend.Compile(field, r1cs.NewBuilder, c) + if err != nil { + log.Println(1) + return err + } + // generate witness + witness, err := frontend.NewWitness(w, field) + if err != nil { + log.Println(2) + return err + } + // get public witness + pubWitness, err := witness.Public() + if err != nil { + log.Println(3) + return err + } + // generate proving and verifying keys + pk, vk, err := groth16.Setup(ccs) + if err != nil { + log.Println(4) + return err + } + // generate proof + proof, err := groth16.Prove(ccs, pk, witness) + if err != nil { + log.Println(5) + return err + } + // write proof into a buffer + var buf bytes.Buffer + _, err = proof.WriteRawTo(&buf) + if err != nil { + log.Println(6) + return err + } + proofBytes := buf.Bytes() + // compose the proof for solidity + type SolidityProof struct { + Ar [2]*big.Int `json:"Ar"` + Bs [2][2]*big.Int `json:"Bs"` + Krs [2]*big.Int `json:"Krs"` + } + p := SolidityProof{} + // proof.Ar, proof.Bs, proof.Krs + const fpSize = 4 * 8 + p.Ar[0] = new(big.Int).SetBytes(proofBytes[fpSize*0 : fpSize*1]) + p.Ar[1] = new(big.Int).SetBytes(proofBytes[fpSize*1 : fpSize*2]) + p.Bs[0][0] = new(big.Int).SetBytes(proofBytes[fpSize*2 : fpSize*3]) + p.Bs[0][1] = new(big.Int).SetBytes(proofBytes[fpSize*3 : fpSize*4]) + p.Bs[1][0] = new(big.Int).SetBytes(proofBytes[fpSize*4 : fpSize*5]) + p.Bs[1][1] = new(big.Int).SetBytes(proofBytes[fpSize*5 : fpSize*6]) + p.Krs[0] = new(big.Int).SetBytes(proofBytes[fpSize*6 : fpSize*7]) + p.Krs[1] = new(big.Int).SetBytes(proofBytes[fpSize*7 : fpSize*8]) + // write proof into a file + prooffd, err := os.Create(fmt.Sprintf("%s_proof.json", name)) + if err != nil { + log.Println(7) + return err + } + defer prooffd.Close() + bProof, err := json.Marshal(p) + if err != nil { + log.Println(8) + return err + } + _, err = prooffd.Write(bProof) + if err != nil { + log.Println(9) + return err + } + // generate solidity verifier + solfd, err := os.Create(fmt.Sprintf("%s.sol", name)) + if err != nil { + log.Println(10) + return err + } + defer solfd.Close() + // write verifier + err = vk.ExportSolidity(solfd) + if err != nil { + log.Println(11) + return err + } + // generate also the json of the public witness + schema, err := frontend.NewSchema(w) + if err != nil { + log.Println(12) + return err + } + jsonWitness, err := pubWitness.ToJSON(schema) + if err != nil { + log.Println(13) + return err + } + pubWitnessJSONfd, err := os.Create(fmt.Sprintf("%s_witness.json", name)) + if err != nil { + log.Println(14) + return err + } + defer pubWitnessJSONfd.Close() + _, err = pubWitnessJSONfd.Write(jsonWitness) + if err != nil { + log.Println(15) + return err + } + return nil +}