Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
cb09cb4
feat: extended tests, use interface for hash instead of mimc
ThomasPiellard Apr 19, 2022
2c5c4eb
feat: removed proof helper in merkle tree
ThomasPiellard May 2, 2022
c0629da
feat: removed deprecated test
ThomasPiellard May 2, 2022
bde197b
feat: modifs on rollup example to use new merkle proof circuit
ThomasPiellard May 3, 2022
6ff8d2e
fix: call reset() on the hash function in leafSum
ThomasPiellard May 3, 2022
6a7b754
feat: old Merkle proof circuits are removed
ThomasPiellard May 3, 2022
acfecb5
fix: fixed rollup tests
ThomasPiellard May 3, 2022
054b64e
fix: fixed unconstrained public inputs
ThomasPiellard May 3, 2022
8f7abc7
fix: all inputs are constrained in rollup example circuit
ThomasPiellard May 4, 2022
4eb569d
feat: removed deprecated code
ThomasPiellard May 4, 2022
dee8267
feat: removed IgnoreUnconstrainedInputs option in rollup test
ThomasPiellard May 4, 2022
5ccf897
feat: snark-fiatShamir test uses real string
ThomasPiellard May 5, 2022
de50c0e
feat: Fiat Shamir derivations OK
ThomasPiellard May 10, 2022
64c24e4
refactor: the leaf is passed as argument for verifying Merkle proof
ThomasPiellard May 11, 2022
2500faf
feat: merkle proofs + rounds consistency ok
ThomasPiellard May 13, 2022
5a0f906
feat: hints wires are constrained
ThomasPiellard May 15, 2022
15876a9
feat: add main method to verify proof regardless of the salt
ThomasPiellard May 24, 2022
92c57e6
Merge branch 'develop' into feat/fri_verifier_circuit
gbotrel Jun 7, 2022
3159ae1
build: fix staticcheck errors
gbotrel Jun 7, 2022
430baad
build: re ran go generate
gbotrel Jun 7, 2022
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
97 changes: 63 additions & 34 deletions examples/rollup/circuit.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ import (
)

const (
nbAccounts = 16 // 16 accounts so we know that the proof length is 5
depth = 5 // size fo the inclusion proofs
batchSize = 1 // nbTranfers to batch in a proof
nbAccounts = 16 // 16 accounts so we know that the proof length is 5
depth = 5 // size fo the inclusion proofs
BatchSizeCircuit = 1 // nbTranfers to batch in a proof
)

// Circuit "toy" rollup circuit where an operator can generate a proof that he processed
Expand All @@ -38,36 +38,32 @@ type Circuit struct {
// SECRET INPUTS

// list of accounts involved before update and their public keys
SenderAccountsBefore [batchSize]AccountConstraints
ReceiverAccountsBefore [batchSize]AccountConstraints
PublicKeysSender [batchSize]eddsa.PublicKey
SenderAccountsBefore [BatchSizeCircuit]AccountConstraints
ReceiverAccountsBefore [BatchSizeCircuit]AccountConstraints
PublicKeysSender [BatchSizeCircuit]eddsa.PublicKey

// list of accounts involved after update and their public keys
SenderAccountsAfter [batchSize]AccountConstraints
ReceiverAccountsAfter [batchSize]AccountConstraints
PublicKeysReceiver [batchSize]eddsa.PublicKey
SenderAccountsAfter [BatchSizeCircuit]AccountConstraints
ReceiverAccountsAfter [BatchSizeCircuit]AccountConstraints
PublicKeysReceiver [BatchSizeCircuit]eddsa.PublicKey

// list of transactions
Transfers [batchSize]TransferConstraints
Transfers [BatchSizeCircuit]TransferConstraints

// list of proofs corresponding to sender account
MerkleProofsSenderBefore [batchSize][depth]frontend.Variable
MerkleProofsSenderAfter [batchSize][depth]frontend.Variable
MerkleProofHelperSenderBefore [batchSize][depth - 1]frontend.Variable
MerkleProofHelperSenderAfter [batchSize][depth - 1]frontend.Variable

// list of proofs corresponding to receiver account
MerkleProofsReceiverBefore [batchSize][depth]frontend.Variable
MerkleProofsReceiverAfter [batchSize][depth]frontend.Variable
MerkleProofHelperReceiverBefore [batchSize][depth - 1]frontend.Variable
MerkleProofHelperReceiverAfter [batchSize][depth - 1]frontend.Variable
// list of proofs corresponding to sender and receiver accounts
MerkleProofReceiverBefore [BatchSizeCircuit]merkle.MerkleProof
MerkleProofReceiverAfter [BatchSizeCircuit]merkle.MerkleProof
MerkleProofSenderBefore [BatchSizeCircuit]merkle.MerkleProof
MerkleProofSenderAfter [BatchSizeCircuit]merkle.MerkleProof
LeafReceiver [BatchSizeCircuit]frontend.Variable
LeafSender [BatchSizeCircuit]frontend.Variable

// ---------------------------------------------------------------------------------------------
// PUBLIC INPUTS

// list of root hashes
RootHashesBefore [batchSize]frontend.Variable `gnark:",public"`
RootHashesAfter [batchSize]frontend.Variable `gnark:",public"`
RootHashesBefore [BatchSizeCircuit]frontend.Variable `gnark:",public"`
RootHashesAfter [BatchSizeCircuit]frontend.Variable `gnark:",public"`
}

// AccountConstraints accounts encoded as constraints
Expand All @@ -89,7 +85,7 @@ type TransferConstraints struct {

func (circuit *Circuit) postInit(api frontend.API) error {

for i := 0; i < batchSize; i++ {
for i := 0; i < BatchSizeCircuit; i++ {

// setting the sender accounts before update
circuit.SenderAccountsBefore[i].PubKey = circuit.PublicKeysSender[i]
Expand All @@ -108,12 +104,28 @@ func (circuit *Circuit) postInit(api frontend.API) error {
circuit.Transfers[i].SenderPubKey = circuit.PublicKeysSender[i]
circuit.Transfers[i].ReceiverPubKey = circuit.PublicKeysReceiver[i]

// allocate the slices for the Merkle proofs
// circuit.allocateSlicesMerkleProofs()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this commented?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Allocating the slices for the Merkle proof is only necessary when creating the full circuit and not for testing sub circuits


}
return nil
}

func (circuit *Circuit) allocateSlicesMerkleProofs() {

for i := 0; i < BatchSizeCircuit; i++ {
// allocating slice for the Merkle paths
circuit.MerkleProofReceiverBefore[i].Path = make([]frontend.Variable, depth)
circuit.MerkleProofReceiverAfter[i].Path = make([]frontend.Variable, depth)
circuit.MerkleProofSenderBefore[i].Path = make([]frontend.Variable, depth)
circuit.MerkleProofSenderAfter[i].Path = make([]frontend.Variable, depth)
}

}

// Define declares the circuit's constraints
func (circuit *Circuit) Define(api frontend.API) error {

if err := circuit.postInit(api); err != nil {
return err
}
Expand All @@ -123,16 +135,29 @@ func (circuit *Circuit) Define(api frontend.API) error {
return err
}

// creation of the circuit
for i := 0; i < batchSize; i++ {

// verify the sender and receiver accounts exist before the update
merkle.VerifyProof(api, hFunc, circuit.RootHashesBefore[i], circuit.MerkleProofsSenderBefore[i][:], circuit.MerkleProofHelperSenderBefore[i][:])
merkle.VerifyProof(api, hFunc, circuit.RootHashesBefore[i], circuit.MerkleProofsReceiverBefore[i][:], circuit.MerkleProofHelperReceiverBefore[i][:])

// verify the sender and receiver accounts exist after the update
merkle.VerifyProof(api, hFunc, circuit.RootHashesAfter[i], circuit.MerkleProofsSenderAfter[i][:], circuit.MerkleProofHelperSenderAfter[i][:])
merkle.VerifyProof(api, hFunc, circuit.RootHashesAfter[i], circuit.MerkleProofsReceiverAfter[i][:], circuit.MerkleProofHelperReceiverAfter[i][:])
// verifications of:
// - Merkle proofs of the accounts
// - the signatures
// - accounts' balance consistency
for i := 0; i < BatchSizeCircuit; i++ {

// the root hashes of the Merkle path must match the public ones given in the circuit
api.AssertIsEqual(circuit.RootHashesBefore[i], circuit.MerkleProofReceiverBefore[i].RootHash)
api.AssertIsEqual(circuit.RootHashesBefore[i], circuit.MerkleProofSenderBefore[i].RootHash)
api.AssertIsEqual(circuit.RootHashesAfter[i], circuit.MerkleProofReceiverAfter[i].RootHash)
api.AssertIsEqual(circuit.RootHashesAfter[i], circuit.MerkleProofSenderAfter[i].RootHash)

// the leafs of the Merkle proofs must match the index of the accounts
api.AssertIsEqual(circuit.ReceiverAccountsBefore[i].Index, circuit.LeafReceiver[i])
api.AssertIsEqual(circuit.ReceiverAccountsAfter[i].Index, circuit.LeafReceiver[i])
api.AssertIsEqual(circuit.SenderAccountsBefore[i].Index, circuit.LeafSender[i])
api.AssertIsEqual(circuit.SenderAccountsAfter[i].Index, circuit.LeafSender[i])

// verify the inclusion proofs
circuit.MerkleProofReceiverBefore[i].VerifyProof(api, &hFunc, circuit.LeafReceiver[i])
circuit.MerkleProofSenderBefore[i].VerifyProof(api, &hFunc, circuit.LeafSender[i])
circuit.MerkleProofReceiverAfter[i].VerifyProof(api, &hFunc, circuit.LeafReceiver[i])
circuit.MerkleProofSenderAfter[i].VerifyProof(api, &hFunc, circuit.LeafSender[i])

// verify the transaction transfer
err := verifyTransferSignature(api, circuit.Transfers[i], hFunc)
Expand All @@ -150,6 +175,9 @@ func (circuit *Circuit) Define(api frontend.API) error {
// verifySignatureTransfer ensures that the signature of the transfer is valid
func verifyTransferSignature(api frontend.API, t TransferConstraints, hFunc mimc.MiMC) error {

// Reset the hash state!
hFunc.Reset()

// the signature is on h(nonce ∥ amount ∥ senderpubKey (x&y) ∥ receiverPubkey(x&y))
hFunc.Write(t.Nonce, t.Amount, t.SenderPubKey.A.X, t.SenderPubKey.A.Y, t.ReceiverPubKey.A.X, t.ReceiverPubKey.A.Y)
htransfer := hFunc.Sum()
Expand All @@ -172,6 +200,7 @@ func verifyAccountUpdated(api frontend.API, from, to, fromUpdated, toUpdated Acc
// ensure that nonce is correctly updated
nonceUpdated := api.Add(from.Nonce, 1)
api.AssertIsEqual(nonceUpdated, fromUpdated.Nonce)
api.AssertIsEqual(to.Nonce, toUpdated.Nonce)

// ensures that the amount is less than the balance
api.AssertIsLessOrEqual(amount, from.Balance)
Expand Down
51 changes: 40 additions & 11 deletions examples/rollup/circuit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import (
"testing"

"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/backend"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/std/accumulator/merkle"
"github.com/consensys/gnark/std/hash/mimc"
"github.com/consensys/gnark/test"
)
Expand Down Expand Up @@ -77,26 +77,30 @@ func TestCircuitSignature(t *testing.T) {
assert := test.NewAssert(t)

var signatureCircuit circuitSignature
for i := 0; i < BatchSizeCircuit; i++ {
signatureCircuit.MerkleProofReceiverBefore[i].Path = make([]frontend.Variable, depth)
signatureCircuit.MerkleProofReceiverAfter[i].Path = make([]frontend.Variable, depth)
signatureCircuit.MerkleProofSenderBefore[i].Path = make([]frontend.Variable, depth)
signatureCircuit.MerkleProofSenderAfter[i].Path = make([]frontend.Variable, depth)
}

assert.ProverSucceeded(&signatureCircuit, &operator.witnesses, test.WithCurves(ecc.BN254), test.WithCompileOpts(frontend.IgnoreUnconstrainedInputs()))

}

type circuitInclusionProof Circuit

// Circuit implements part of the rollup circuit only by delcaring a subset of the constraints
func (t *circuitInclusionProof) Define(api frontend.API) error {
if err := (*Circuit)(t).postInit(api); err != nil {
return err
}

hashFunc, err := mimc.NewMiMC(api)
if err != nil {
return err
}
merkle.VerifyProof(api, hashFunc, t.RootHashesBefore[0], t.MerkleProofsSenderBefore[0][:], t.MerkleProofHelperSenderBefore[0][:])
merkle.VerifyProof(api, hashFunc, t.RootHashesBefore[0], t.MerkleProofsReceiverBefore[0][:], t.MerkleProofHelperReceiverBefore[0][:])

merkle.VerifyProof(api, hashFunc, t.RootHashesAfter[0], t.MerkleProofsReceiverAfter[0][:], t.MerkleProofHelperReceiverAfter[0][:])
merkle.VerifyProof(api, hashFunc, t.RootHashesAfter[0], t.MerkleProofsReceiverAfter[0][:], t.MerkleProofHelperReceiverAfter[0][:])
t.MerkleProofReceiverBefore[0].VerifyProof(api, &hashFunc, t.LeafReceiver[0])
t.MerkleProofReceiverAfter[0].VerifyProof(api, &hashFunc, t.LeafReceiver[0])
t.MerkleProofSenderBefore[0].VerifyProof(api, &hashFunc, t.LeafSender[0])
t.MerkleProofSenderAfter[0].VerifyProof(api, &hashFunc, t.LeafSender[0])

return nil
}
Expand Down Expand Up @@ -139,19 +143,33 @@ func TestCircuitInclusionProof(t *testing.T) {
// verifies the proofs of inclusion of the transfer
assert := test.NewAssert(t)

// we allocate the slices of the circuit before compiling it
var inclusionProofCircuit circuitInclusionProof
for i := 0; i < BatchSizeCircuit; i++ {
inclusionProofCircuit.MerkleProofReceiverBefore[i].Path = make([]frontend.Variable, depth)
inclusionProofCircuit.MerkleProofReceiverAfter[i].Path = make([]frontend.Variable, depth)
inclusionProofCircuit.MerkleProofSenderBefore[i].Path = make([]frontend.Variable, depth)
inclusionProofCircuit.MerkleProofSenderAfter[i].Path = make([]frontend.Variable, depth)
}

assert.ProverSucceeded(&inclusionProofCircuit, &operator.witnesses, test.WithCurves(ecc.BN254), test.WithCompileOpts(frontend.IgnoreUnconstrainedInputs()))
assert.ProverSucceeded(
&inclusionProofCircuit,
&operator.witnesses,
test.WithCurves(ecc.BN254),
test.WithCompileOpts(frontend.IgnoreUnconstrainedInputs()),
test.WithBackends(backend.GROTH16))

}

type circuitUpdateAccount Circuit

// Circuit implements part of the rollup circuit only by delcaring a subset of the constraints
func (t *circuitUpdateAccount) Define(api frontend.API) error {

if err := (*Circuit)(t).postInit(api); err != nil {
return err
}

verifyAccountUpdated(api, t.SenderAccountsBefore[0], t.ReceiverAccountsBefore[0],
t.SenderAccountsAfter[0], t.ReceiverAccountsAfter[0], t.Transfers[0].Amount)
return nil
Expand Down Expand Up @@ -195,6 +213,7 @@ func TestCircuitUpdateAccount(t *testing.T) {
assert := test.NewAssert(t)

var updateAccountCircuit circuitUpdateAccount
(*Circuit)(&updateAccountCircuit).allocateSlicesMerkleProofs()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why the cast?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type circuitUpdateAccount inherits the fields but not the methods of Circuit


assert.ProverSucceeded(&updateAccountCircuit, &operator.witnesses, test.WithCurves(ecc.BN254), test.WithCompileOpts(frontend.IgnoreUnconstrainedInputs()))

Expand Down Expand Up @@ -239,8 +258,18 @@ func TestCircuitFull(t *testing.T) {
// verifies the proofs of inclusion of the transfer

var rollupCircuit Circuit
for i := 0; i < BatchSizeCircuit; i++ {
rollupCircuit.MerkleProofReceiverBefore[i].Path = make([]frontend.Variable, depth)
rollupCircuit.MerkleProofReceiverAfter[i].Path = make([]frontend.Variable, depth)
rollupCircuit.MerkleProofSenderBefore[i].Path = make([]frontend.Variable, depth)
rollupCircuit.MerkleProofSenderAfter[i].Path = make([]frontend.Variable, depth)
}

// TODO full circuit has some unconstrained inputs, that's odd.
assert.ProverSucceeded(&rollupCircuit, &operator.witnesses, test.WithCurves(ecc.BN254), test.WithCompileOpts(frontend.IgnoreUnconstrainedInputs()))
assert.ProverSucceeded(
&rollupCircuit,
&operator.witnesses,
test.WithCurves(ecc.BN254),
test.WithBackends(backend.GROTH16))

}
4 changes: 4 additions & 0 deletions examples/rollup/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,8 @@ var (

// ErrNonce inconsistant nonce between transfer and account
ErrNonce = errors.New("incorrect nonce")

// ErrIndexConsistency the map publicKey(string) -> index(int) gives acces to the account position.
// Account has a field index, that should match position.
ErrIndexConsistency = errors.New("account's position should match account's index")
)
Loading