arnaucube
arnaucube/go-circom-prover-verifierPublic Self-hosted repository
Merge pull request #5 from iden3/feature/refactor-circuits

Feature/refactor circuits
arnau 17317030+arnaucube@users.noreply.github.com
Sun, 26 Apr 2020 21:37:19 +0200
commit

dc4ac0b3502138965cbf2f509edc03474988e707

parent

36917850547a4ee02b4e4583dc3ad216c226bc0a

M .github/workflows/main.yml → .github/workflows/main.yml

@@ -26,7 +26,7 @@ - name: Checkout code

uses: actions/checkout@v2 - name: Compile circuits and execute Go tests run: | - sh ./compile-circuits.sh - go run cli/cli.go -prove -provingkey=testdata/small/proving_key.json -witness=testdata/small/witness.json -proof=testdata/small/proof.json -public=testdata/small/public.json - go run cli/cli.go -prove -provingkey=testdata/big/proving_key.json -witness=testdata/big/witness.json -proof=testdata/big/proof.json -public=testdata/big/public.json + cd testdata && sh ./compile-circuits.sh && cd .. + go run cli/cli.go -prove -provingkey=testdata/circuit1k/proving_key.json -witness=testdata/circuit1k/witness.json -proof=testdata/circuit1k/proof.json -public=testdata/circuit1k/public.json + go run cli/cli.go -prove -provingkey=testdata/circuit5k/proving_key.json -witness=testdata/circuit5k/witness.json -proof=testdata/circuit5k/proof.json -public=testdata/circuit5k/public.json go test ./...
M .gitignore → .gitignore

@@ -4,5 +4,5 @@ testdata/*/*.cpp

testdata/*/*.sym testdata/*/*.r1cs testdata/*/*.sol -!testdata/*/input.json +!testdata/*/inputs.json cli/*.json
M cli/cli.go → cli/cli.go

@@ -5,6 +5,7 @@ "encoding/json"

"flag" "fmt" "io/ioutil" + "time" "github.com/iden3/go-circom-prover-verifier/parsers" "github.com/iden3/go-circom-prover-verifier/prover"

@@ -46,6 +47,8 @@ }

func cmdProve(provingKeyPath, witnessPath, proofPath, publicPath string) error { fmt.Println("zkSNARK Groth16 prover") + + fmt.Println("Reading proving key file:", provingKeyPath) provingKeyJson, err := ioutil.ReadFile(provingKeyPath) if err != nil { return err

@@ -55,6 +58,7 @@ if err != nil {

return err } + fmt.Println("Reading witness file:", witnessPath) witnessJson, err := ioutil.ReadFile(witnessPath) if err != nil { return err

@@ -64,10 +68,13 @@ if err != nil {

return err } + fmt.Println("Generating the proof") + beforeT := time.Now() proof, pubSignals, err := prover.GenerateProof(pk, w) if err != nil { return err } + fmt.Println("proof generation time elapsed:", time.Since(beforeT)) proofStr, err := parsers.ProofToJson(proof) if err != nil {
D compile-circuits.sh

@@ -1,21 +0,0 @@

-#!/bin/sh - -echo "testdata/small/circuit.circom" -cd testdata/small -echo "compiling circuit" -circom circuit.circom -r1cs --wasm --sym -echo "generating setup" -snarkjs setup -sed -i 's/null/["0","0","0"]/g' proving_key.json -echo "calculating witness" -snarkjs calculatewitness --wasm circuit.wasm --input input.json --witness witness.json - -echo "\ntestdata/big/circuit.circom" -cd ../big -echo "compiling circuit" -circom circuit.circom -r1cs --wasm --sym -echo "generating setup" -snarkjs setup -sed -i 's/null/["0","0","0"]/g' proving_key.json -echo "calculating witness" -snarkjs calculatewitness --wasm circuit.wasm --input input.json --witness witness.json
M prover/prover.go → prover/prover.go

@@ -73,39 +73,39 @@ proof.B = new(bn256.G2).ScalarBaseMult(big.NewInt(0))

proof.C = new(bn256.G1).ScalarBaseMult(big.NewInt(0)) proofBG1 := new(bn256.G1).ScalarBaseMult(big.NewInt(0)) - var waitGroup sync.WaitGroup - waitGroup.Add(4) - go func(wg *sync.WaitGroup) { + var wg sync.WaitGroup + wg.Add(4) + go func() { for i := 0; i < pk.NVars; i++ { proof.A = new(bn256.G1).Add(proof.A, new(bn256.G1).ScalarMult(pk.A[i], w[i])) } wg.Done() - }(&waitGroup) - go func(wg *sync.WaitGroup) { + }() + go func() { for i := 0; i < pk.NVars; i++ { proof.B = new(bn256.G2).Add(proof.B, new(bn256.G2).ScalarMult(pk.B2[i], w[i])) } wg.Done() - }(&waitGroup) - go func(wg *sync.WaitGroup) { + }() + go func() { for i := 0; i < pk.NVars; i++ { proofBG1 = new(bn256.G1).Add(proofBG1, new(bn256.G1).ScalarMult(pk.B1[i], w[i])) } wg.Done() - }(&waitGroup) - go func(wg *sync.WaitGroup) { + }() + go func() { for i := pk.NPublic + 1; i < pk.NVars; i++ { proof.C = new(bn256.G1).Add(proof.C, new(bn256.G1).ScalarMult(pk.C[i], w[i])) } wg.Done() - }(&waitGroup) - waitGroup.Wait() + }() + wg.Wait() h := calculateH(pk, w) - var waitGroup2 sync.WaitGroup - waitGroup2.Add(2) - go func(wg *sync.WaitGroup) { + var wg2 sync.WaitGroup + wg2.Add(2) + go func() { proof.A = new(bn256.G1).Add(proof.A, pk.VkAlpha1) proof.A = new(bn256.G1).Add(proof.A, new(bn256.G1).ScalarMult(pk.VkDelta1, r))

@@ -114,15 +114,15 @@ proof.B = new(bn256.G2).Add(proof.B, new(bn256.G2).ScalarMult(pk.VkDelta2, s))

proofBG1 = new(bn256.G1).Add(proofBG1, pk.VkBeta1) proofBG1 = new(bn256.G1).Add(proofBG1, new(bn256.G1).ScalarMult(pk.VkDelta1, s)) - wg.Done() - }(&waitGroup2) - go func(wg *sync.WaitGroup) { + wg2.Done() + }() + go func() { for i := 0; i < len(h); i++ { proof.C = new(bn256.G1).Add(proof.C, new(bn256.G1).ScalarMult(pk.HExps[i], h[i])) } - wg.Done() - }(&waitGroup2) - waitGroup2.Wait() + wg2.Done() + }() + wg2.Wait() proof.C = new(bn256.G1).Add(proof.C, new(bn256.G1).ScalarMult(proof.A, s)) proof.C = new(bn256.G1).Add(proof.C, new(bn256.G1).ScalarMult(proofBG1, r))
M prover/prover_test.go → prover/prover_test.go

@@ -4,65 +4,29 @@ import (

"encoding/json" "fmt" "io/ioutil" - "math/big" "testing" "time" "github.com/iden3/go-circom-prover-verifier/parsers" - "github.com/iden3/go-circom-prover-verifier/types" "github.com/iden3/go-circom-prover-verifier/verifier" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -func TestSmallCircuitGenerateProof(t *testing.T) { - provingKeyJson, err := ioutil.ReadFile("../testdata/small/proving_key.json") - require.Nil(t, err) - pk, err := parsers.ParsePk(provingKeyJson) - require.Nil(t, err) - - witnessJson, err := ioutil.ReadFile("../testdata/small/witness.json") - require.Nil(t, err) - w, err := parsers.ParseWitness(witnessJson) - require.Nil(t, err) - - assert.Equal(t, types.Witness{big.NewInt(1), big.NewInt(33), big.NewInt(3), big.NewInt(11)}, w) - - beforeT := time.Now() - proof, pubSignals, err := GenerateProof(pk, w) - assert.Nil(t, err) - fmt.Println("proof generation time elapsed:", time.Since(beforeT)) - - proofStr, err := parsers.ProofToJson(proof) - assert.Nil(t, err) - - err = ioutil.WriteFile("../testdata/small/proof.json", proofStr, 0644) - assert.Nil(t, err) - publicStr, err := json.Marshal(parsers.ArrayBigIntToString(pubSignals)) - assert.Nil(t, err) - err = ioutil.WriteFile("../testdata/small/public.json", publicStr, 0644) - assert.Nil(t, err) - - // verify the proof - vkJson, err := ioutil.ReadFile("../testdata/small/verification_key.json") - require.Nil(t, err) - vk, err := parsers.ParseVk(vkJson) - require.Nil(t, err) - - v := verifier.Verify(vk, proof, pubSignals) - assert.True(t, v) - - // to verify the proof with snarkjs: - // snarkjs verify --vk testdata/small/verification_key.json -p testdata/small/proof.json --pub testdata/small/public.json +func TestCircuitsGenerateProof(t *testing.T) { + testCircuitGenerateProof(t, "circuit1k") // 1000 constraints + testCircuitGenerateProof(t, "circuit5k") // 5000 constraints + // testCircuitGenerateProof(t, "circuit10k") // 10000 constraints + // testCircuitGenerateProof(t, "circuit20k") // 20000 constraints } -func TestBigCircuitGenerateProof(t *testing.T) { - provingKeyJson, err := ioutil.ReadFile("../testdata/big/proving_key.json") +func testCircuitGenerateProof(t *testing.T, circuit string) { + provingKeyJson, err := ioutil.ReadFile("../testdata/" + circuit + "/proving_key.json") require.Nil(t, err) pk, err := parsers.ParsePk(provingKeyJson) require.Nil(t, err) - witnessJson, err := ioutil.ReadFile("../testdata/big/witness.json") + witnessJson, err := ioutil.ReadFile("../testdata/" + circuit + "/witness.json") require.Nil(t, err) w, err := parsers.ParseWitness(witnessJson) require.Nil(t, err)

@@ -75,15 +39,15 @@

proofStr, err := parsers.ProofToJson(proof) assert.Nil(t, err) - err = ioutil.WriteFile("../testdata/big/proof.json", proofStr, 0644) + err = ioutil.WriteFile("../testdata/"+circuit+"/proof.json", proofStr, 0644) assert.Nil(t, err) publicStr, err := json.Marshal(parsers.ArrayBigIntToString(pubSignals)) assert.Nil(t, err) - err = ioutil.WriteFile("../testdata/big/public.json", publicStr, 0644) + err = ioutil.WriteFile("../testdata/"+circuit+"/public.json", publicStr, 0644) assert.Nil(t, err) // verify the proof - vkJson, err := ioutil.ReadFile("../testdata/big/verification_key.json") + vkJson, err := ioutil.ReadFile("../testdata/" + circuit + "/verification_key.json") require.Nil(t, err) vk, err := parsers.ParseVk(vkJson) require.Nil(t, err)

@@ -92,62 +56,17 @@ v := verifier.Verify(vk, proof, pubSignals)

assert.True(t, v) // to verify the proof with snarkjs: - // snarkjs verify --vk testdata/big/verification_key.json -p testdata/big/proof.json --pub testdata/big/public.json -} - -func TestIdStateCircuitGenerateProof(t *testing.T) { - // this test is to execute the proof generation for a bigger circuit - // (arround 22500 constraints) - // - // to see the time needed to execute this - // test Will need the ../testdata/idstate-circuit compiled & - // trustedsetup files (generated in - // https://github.com/iden3/go-zksnark-full-flow-example) - if false { - fmt.Println("\nTestIdStateCircuitGenerateProof activated") - provingKeyJson, err := ioutil.ReadFile("../testdata/idstate-circuit/proving_key.json") - require.Nil(t, err) - pk, err := parsers.ParsePk(provingKeyJson) - require.Nil(t, err) - - witnessJson, err := ioutil.ReadFile("../testdata/idstate-circuit/witness.json") - require.Nil(t, err) - w, err := parsers.ParseWitness(witnessJson) - require.Nil(t, err) - - beforeT := time.Now() - proof, pubSignals, err := GenerateProof(pk, w) - assert.Nil(t, err) - fmt.Println("proof generation time elapsed:", time.Since(beforeT)) - - proofStr, err := parsers.ProofToJson(proof) - assert.Nil(t, err) - - err = ioutil.WriteFile("../testdata/idstate-circuit/proof.json", proofStr, 0644) - assert.Nil(t, err) - publicStr, err := json.Marshal(parsers.ArrayBigIntToString(pubSignals)) - assert.Nil(t, err) - err = ioutil.WriteFile("../testdata/idstate-circuit/public.json", publicStr, 0644) - assert.Nil(t, err) - - // verify the proof - vkJson, err := ioutil.ReadFile("../testdata/idstate-circuit/verification_key.json") - require.Nil(t, err) - vk, err := parsers.ParseVk(vkJson) - require.Nil(t, err) - - v := verifier.Verify(vk, proof, pubSignals) - assert.True(t, v) - } + // snarkjs verify --vk testdata/circuitX/verification_key.json -p testdata/circuitX/proof.json --pub testdata/circuitX/public.json } func BenchmarkGenerateProof(b *testing.B) { - provingKeyJson, err := ioutil.ReadFile("../testdata/big/proving_key.json") + // benchmark with a circuit of 10000 constraints + provingKeyJson, err := ioutil.ReadFile("../testdata/circuit1/proving_key.json") require.Nil(b, err) pk, err := parsers.ParsePk(provingKeyJson) require.Nil(b, err) - witnessJson, err := ioutil.ReadFile("../testdata/big/witness.json") + witnessJson, err := ioutil.ReadFile("../testdata/circuit1/witness.json") require.Nil(b, err) w, err := parsers.ParseWitness(witnessJson) require.Nil(b, err)
M testdata/big/circuit.circom → testdata/circuit10k/circuit.circom

@@ -1,4 +1,4 @@

-template A(n) { +template TestConstraints(n) { signal input in; signal output out;

@@ -11,4 +11,4 @@ }

out <== intermediate[n-1]; } -component main = A(1000); // bigger takes too much time on generating trusted setup +component main = TestConstraints(10000);
D testdata/big/input.json

@@ -1,1 +0,0 @@

-{ "in": 1}
A testdata/circuit10k/inputs.json

@@ -0,0 +1,1 @@

+{"in":"1"}
A testdata/circuit1k/circuit.circom

@@ -0,0 +1,14 @@

+template TestConstraints(n) { + signal input in; + signal output out; + + signal intermediate[n]; + + intermediate[0] <== in; + for (var i=1; i<n; i++) { + intermediate[i] <== intermediate[i-1] * intermediate[i-1] + i; + } + out <== intermediate[n-1]; +} + +component main = TestConstraints(1000);
A testdata/circuit1k/inputs.json

@@ -0,0 +1,1 @@

+{"in":"1"}
A testdata/circuit20k/circuit.circom

@@ -0,0 +1,14 @@

+template TestConstraints(n) { + signal input in; + signal output out; + + signal intermediate[n]; + + intermediate[0] <== in; + for (var i=1; i<n; i++) { + intermediate[i] <== intermediate[i-1] * intermediate[i-1] + i; + } + out <== intermediate[n-1]; +} + +component main = TestConstraints(20000);
A testdata/circuit20k/inputs.json

@@ -0,0 +1,1 @@

+{"in":"1"}
A testdata/circuit5k/circuit.circom

@@ -0,0 +1,14 @@

+template TestConstraints(n) { + signal input in; + signal output out; + + signal intermediate[n]; + + intermediate[0] <== in; + for (var i=1; i<n; i++) { + intermediate[i] <== intermediate[i-1] * intermediate[i-1] + i; + } + out <== intermediate[n-1]; +} + +component main = TestConstraints(5000);
A testdata/circuit5k/inputs.json

@@ -0,0 +1,1 @@

+{"in":"1"}
A testdata/clean-gereated-files.sh

@@ -0,0 +1,9 @@

+#!/bin/sh + +# rm */*.json +find */*.json -type f -not -name 'inputs.json' -delete +rm */*.wasm +rm */*.cpp +rm */*.sym +rm */*.r1cs +rm */*.sol
A testdata/compile-circuits.sh

@@ -0,0 +1,42 @@

+#!/bin/sh + +compile_and_ts_and_witness() { + echo $(date +"%T") "circom circuit.circom --r1cs --wasm --sym" + itime="$(date -u +%s)" + circom circuit.circom --r1cs --wasm --sym + ftime="$(date -u +%s)" + echo " ($(($(date -u +%s)-$itime))s)" + + echo $(date +"%T") "snarkjs info -r circuit.r1cs" + snarkjs info -r circuit.r1cs + + echo $(date +"%T") "snarkjs setup" + itime="$(date -u +%s)" + snarkjs setup + echo " ($(($(date -u +%s)-$itime))s)" + echo $(date +"%T") "trusted setup generated" + + sed -i 's/null/["0","0","0"]/g' proving_key.json + + echo "calculating witness" + snarkjs calculatewitness --wasm circuit.wasm --input inputs.json --witness witness.json + + echo $(date +"%T") "snarkjs generateverifier" + itime="$(date -u +%s)" + snarkjs generateverifier + echo " ($(($(date -u +%s)-$itime))s)" + echo $(date +"%T") "generateverifier generated" +} + +echo "compile & trustesetup for circuit1k" +cd circuit1k +compile_and_ts_and_witness +echo "compile & trustesetup for circuit5k" +cd ../circuit5k +compile_and_ts_and_witness +# echo "compile & trustesetup for circuit10k" +# cd ../circuit10k +# compile_and_ts_and_witness +# echo "compile & trustesetup for circuit20k" +# cd ../circuit20k +# compile_and_ts_and_witness
D testdata/small/circuit.circom

@@ -1,9 +0,0 @@

-template Multiplier() { - signal private input a; - signal private input b; - signal output c; - - c <== a*b; -} - -component main = Multiplier();
D testdata/small/input.json

@@ -1,1 +0,0 @@

-{ "a":3, "b": 11}
M verifier/verifier_test.go → verifier/verifier_test.go

@@ -10,12 +10,19 @@ "github.com/stretchr/testify/assert"

"github.com/stretchr/testify/require" ) -func TestVerify1(t *testing.T) { - proofJson, err := ioutil.ReadFile("../testdata/big/proof.json") +func TestVerify(t *testing.T) { + testVerifyCircuit(t, "circuit1k") + testVerifyCircuit(t, "circuit5k") + // testVerifyCircuit(t, "circuit10k") + // testVerifyCircuit(t, "circuit20k") +} + +func testVerifyCircuit(t *testing.T, circuit string) { + proofJson, err := ioutil.ReadFile("../testdata/" + circuit + "/proof.json") require.Nil(t, err) - vkJson, err := ioutil.ReadFile("../testdata/big/verification_key.json") + vkJson, err := ioutil.ReadFile("../testdata/" + circuit + "/verification_key.json") require.Nil(t, err) - publicJson, err := ioutil.ReadFile("../testdata/big/public.json") + publicJson, err := ioutil.ReadFile("../testdata/" + circuit + "/public.json") require.Nil(t, err) public, err := parsers.ParsePublicSignals(publicJson)

@@ -34,11 +41,12 @@ assert.True(t, v)

} func BenchmarkVerify(b *testing.B) { - proofJson, err := ioutil.ReadFile("../testdata/big/proof.json") + // benchmark with circuit2 (10000 constraints) + proofJson, err := ioutil.ReadFile("../testdata/circuit2/proof.json") require.Nil(b, err) - vkJson, err := ioutil.ReadFile("../testdata/big/verification_key.json") + vkJson, err := ioutil.ReadFile("../testdata/circuit2/verification_key.json") require.Nil(b, err) - publicJson, err := ioutil.ReadFile("../testdata/big/public.json") + publicJson, err := ioutil.ReadFile("../testdata/circuit2/public.json") require.Nil(b, err) public, err := parsers.ParsePublicSignals(publicJson)