Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 21 additions & 20 deletions circuits/aggregator/aggregator.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
"github.com/consensys/gnark/std/recursion/plonk"
"github.com/vocdoni/vocdoni-z-sandbox/circuits"
)

Expand All @@ -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]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
Expand All @@ -60,31 +61,31 @@ 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 := 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)
}
// 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 and verify each proof with it
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)
}
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)
}
// verify the proof
// 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)
}
Expand Down
47 changes: 27 additions & 20 deletions circuits/aggregator/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ 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"
"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"
)
Expand All @@ -31,49 +32,55 @@ 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,
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)
circuits.AggregatorCurve.ScalarField(), circuits.VoteVerifierCurve.ScalarField(), persist, srs, srsLagrange)
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
// provided with a dummy circuit stuff and proofs compiled for the main
// 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
}
Expand All @@ -83,7 +90,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
Expand Down
21 changes: 11 additions & 10 deletions circuits/dummy/dummy_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,33 @@ import (
"fmt"
"math/big"

"github.com/consensys/gnark/backend/groth16"
"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/r1cs"
stdgroth16 "github.com/consensys/gnark/std/recursion/groth16"
"github.com/consensys/gnark/frontend/cs/scs"
stdplonk "github.com/consensys/gnark/std/recursion/plonk"
)

func Prove(placeholder, assignment frontend.Circuit, outer *big.Int, field *big.Int, persist bool) (constraint.ConstraintSystem, witness.Witness, groth16.Proof, groth16.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)
}
fullWitness, err := frontend.NewWitness(assignment, field)
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)
}
publicWitness, err := fullWitness.Public()
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)
}
/*
Expand All @@ -53,12 +54,12 @@ 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, 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)
}
pk, vk, err := groth16.Setup(ccs)
pk, vk, err := plonk.Setup(ccs, srs, srsLagrange)
if err != nil {
return nil, nil, nil, fmt.Errorf("setup error: %w", err)
}
Expand Down
38 changes: 37 additions & 1 deletion circuits/dummy/dummy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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))
}
Loading
Loading