11 Commits

Author SHA1 Message Date
arnaucube
5c2aaec1ca Add ProvingKey binary parser
The time on the parsing doesn't improve, as the data from the binary
file needs to be converted to `affine` representation, and then parsed
into the `bn256.G1` & `bn256.G2` formats (Montgomery). But the size of
the ProvingKey files in binary is much smaller, so will be better
handled by the smarthpones.

- Parse time benchmarks:
```
BenchmarkParsePk/Parse_Pk_bin_circuit1k-4         	       2	 563729994 ns/op
BenchmarkParsePk/Parse_Pk_json_circuit1k-4        	  635641	      1941 ns/op
BenchmarkParsePk/Parse_Pk_bin_circuit5k-4         	       1	2637941658 ns/op
BenchmarkParsePk/Parse_Pk_json_circuit5k-4        	       1	2986560185 ns/op
BenchmarkParsePk/Parse_Pk_bin_circuit10k-4        	       1	5337639150 ns/op
BenchmarkParsePk/Parse_Pk_json_circuit10k-4       	       1	6149568824 ns/op
BenchmarkParsePk/Parse_Pk_bin_circuit20k-4        	       1	10533654623 ns/op
BenchmarkParsePk/Parse_Pk_json_circuit20k-4       	       1	11657326851 ns/op
```

- Size of ProvingKey file for a circuit of 50k constraints:
```
circuit 20k constraints:
10097812 bytes of proving_key.bin
29760049 bytes of proving_key.json

circuit 50k constraints:
24194964 bytes of proving_key.bin
71484081 bytes of proving_key.json
```
2020-05-20 12:25:27 +02:00
Eduard S
1aa316cbd2 Merge pull request #11 from iden3/feature/proof-parsers
Add proof parsers to string (decimal & hex)
2020-05-07 12:15:08 +02:00
arnaucube
0f48cfa2a5 Add proof parsers to string (decimal & hex)
Also adds ProofToSmartContractFormat, which returns a ProofString as the
proof.B elements swap is not a valid point for the bn256.G2 format.

Also unexports internal structs and methods of the prover package.
Also apply golint.
2020-05-06 14:45:44 +02:00
Eduard S
6ec118d4e2 Merge pull request #10 from iden3/feature/tables2
Add G1/G2 table calculation functionality
2020-05-06 11:43:06 +02:00
druiz0992
423d5f0ce7 Add G1/G2 table calculation functionality 2020-05-06 09:27:15 +02:00
arnaucube
a314ecc02f Add witness parser from binary file 2020-04-30 10:33:17 +02:00
arnaucube
700f2a4503 Fix prover benchmark file paths, update readme, and other small updates 2020-04-29 10:27:31 +02:00
arnau
02fc1ea6f7 Merge pull request #7 from iden3/feature/paralelism2
Implement more agressive parallelism
2020-04-28 20:14:06 +02:00
arnaucube
16054cc679 Remove inner prints 2020-04-28 20:09:16 +02:00
arnau
296dc53736 Merge pull request #6 from iden3/ed255-patch-1-1
Fix setting node version in gh workflow
2020-04-28 20:08:00 +02:00
Eduard S
8f09322e16 Implement more agressive parallelism 2020-04-28 18:21:54 +02:00
18 changed files with 2422 additions and 99 deletions

View File

@@ -18,10 +18,6 @@ jobs:
uses: actions/setup-node@v1
with:
node-version: '10.x'
- name: Install circom
run: npm install -g circom
- name: Install snarkjs
run: npm install -g snarkjs
- name: Checkout code
uses: actions/checkout@v2
- name: Compile circuits and execute Go tests

1
.gitignore vendored
View File

@@ -4,5 +4,6 @@ testdata/*/*.cpp
testdata/*/*.sym
testdata/*/*.r1cs
testdata/*/*.sol
testdata/*/*.bin
!testdata/*/inputs.json
cli/*.json

View File

@@ -1,6 +1,6 @@
# go-circom-prover-verifier [![GoDoc](https://godoc.org/github.com/iden3/go-circom-prover-verifier?status.svg)](https://godoc.org/github.com/iden3/go-circom-prover-verifier) [![Go Report Card](https://goreportcard.com/badge/github.com/iden3/go-circom-prover-verifier)](https://goreportcard.com/report/github.com/iden3/go-circom-prover-verifier) [![Test](https://github.com/iden3/go-circom-prover-verifier/workflows/Test/badge.svg)](https://github.com/iden3/go-circom-prover-verifier/actions?query=workflow%3ATest)
Experimental Go implementation of the [Groth16 protocol](https://eprint.iacr.org/2016/260.pdf) zkSNARK prover & verifier compatible with [circom](https://github.com/iden3/circom).
Go implementation of the [Groth16 protocol](https://eprint.iacr.org/2016/260.pdf) zkSNARK prover & verifier compatible with [circom](https://github.com/iden3/circom).
Using [bn256](https://github.com/ethereum/go-ethereum/tree/master/crypto/bn256/cloudflare) (used by [go-ethereum](https://github.com/ethereum/go-ethereum)) for the Pairing curve operations.
@@ -82,9 +82,9 @@ Usage of /tmp/go-build620318239/b001/exe/cli:
- Prove
```
> go run cli.go -prove -provingkey=../testdata/small/proving_key.json -witness=../testdata/small/witness.json
> go run cli.go -prove -provingkey=../testdata/circuit5k/proving_key.json -witness=../testdata/circuit5k/witness.json
```
- Verify
```
> go run cli.go -verify -verificationkey=../testdata/small/verification_key.json
> go run cli.go -verify -verificationkey=../testdata/circuit5k/verification_key.json
```

View File

@@ -5,6 +5,7 @@ import (
"flag"
"fmt"
"io/ioutil"
"os"
"time"
"github.com/iden3/go-circom-prover-verifier/parsers"
@@ -34,15 +35,15 @@ func main() {
if err != nil {
fmt.Println("Error:", err)
}
return
os.Exit(0)
} else if *verify {
err := cmdVerify(*proofPath, *verificationKeyPath, *publicPath)
if err != nil {
fmt.Println("Error:", err)
}
return
os.Exit(0)
}
fmt.Println("use -help for the list of commands")
flag.PrintDefaults()
}
func cmdProve(provingKeyPath, witnessPath, proofPath, publicPath string) error {

View File

@@ -1,11 +1,15 @@
package parsers
import (
"bufio"
"bytes"
"encoding/binary"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"math/big"
"os"
"strconv"
"strings"
@@ -464,8 +468,35 @@ func stringToG2(h [][]string) (*bn256.G2, error) {
return p, err
}
// ProofToJson outputs the Proof i Json format
func ProofToJson(p *types.Proof) ([]byte, error) {
// ProofStringToSmartContractFormat converts the ProofString to a ProofString in the SmartContract format in a ProofString structure
func ProofStringToSmartContractFormat(s ProofString) ProofString {
var rs ProofString
rs.A = make([]string, 2)
rs.B = make([][]string, 2)
rs.B[0] = make([]string, 2)
rs.B[1] = make([]string, 2)
rs.C = make([]string, 2)
rs.A[0] = s.A[0]
rs.A[1] = s.A[1]
rs.B[0][0] = s.B[0][1]
rs.B[0][1] = s.B[0][0]
rs.B[1][0] = s.B[1][1]
rs.B[1][1] = s.B[1][0]
rs.C[0] = s.C[0]
rs.C[1] = s.C[1]
rs.Protocol = s.Protocol
return rs
}
// ProofToSmartContractFormat converts the *types.Proof to a ProofString in the SmartContract format in a ProofString structure
func ProofToSmartContractFormat(p *types.Proof) ProofString {
s := ProofToString(p)
return ProofStringToSmartContractFormat(s)
}
// ProofToString converts the Proof to ProofString
func ProofToString(p *types.Proof) ProofString {
var ps ProofString
ps.A = make([]string, 3)
ps.B = make([][]string, 3)
@@ -494,5 +525,443 @@ func ProofToJson(p *types.Proof) ([]byte, error) {
ps.Protocol = "groth"
return ps
}
// ProofToJson outputs the Proof i Json format
func ProofToJson(p *types.Proof) ([]byte, error) {
ps := ProofToString(p)
return json.Marshal(ps)
}
// ProofToHex converts the Proof to ProofString with hexadecimal strings
func ProofToHex(p *types.Proof) ProofString {
var ps ProofString
ps.A = make([]string, 3)
ps.B = make([][]string, 3)
ps.B[0] = make([]string, 2)
ps.B[1] = make([]string, 2)
ps.B[2] = make([]string, 2)
ps.C = make([]string, 3)
a := p.A.Marshal()
ps.A[0] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(a[:32]).Bytes())
ps.A[1] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(a[32:64]).Bytes())
ps.A[2] = "1"
b := p.B.Marshal()
ps.B[0][1] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(b[:32]).Bytes())
ps.B[0][0] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(b[32:64]).Bytes())
ps.B[1][1] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(b[64:96]).Bytes())
ps.B[1][0] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(b[96:128]).Bytes())
ps.B[2][0] = "1"
ps.B[2][1] = "0"
c := p.C.Marshal()
ps.C[0] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(c[:32]).Bytes())
ps.C[1] = "0x" + hex.EncodeToString(new(big.Int).SetBytes(c[32:64]).Bytes())
ps.C[2] = "1"
ps.Protocol = "groth"
return ps
}
// ProofToJsonHex outputs the Proof i Json format with hexadecimal strings
func ProofToJsonHex(p *types.Proof) ([]byte, error) {
ps := ProofToHex(p)
return json.Marshal(ps)
}
// ParseWitnessBin parses binary file representation of the Witness into the Witness struct
func ParseWitnessBin(f *os.File) (types.Witness, error) {
var w types.Witness
r := bufio.NewReader(f)
for {
b := make([]byte, 32)
n, err := r.Read(b)
if err == io.EOF {
return w, nil
} else if err != nil {
return nil, err
}
if n != 32 {
return nil, fmt.Errorf("error on value format, expected 32 bytes, got %v", n)
}
w = append(w, new(big.Int).SetBytes(swapEndianness(b[0:32])))
}
}
// swapEndianness swaps the order of the bytes in the slice.
func swapEndianness(b []byte) []byte {
o := make([]byte, len(b))
for i := range b {
o[len(b)-1-i] = b[i]
}
return o
}
func readNBytes(r io.Reader, n int) ([]byte, error) {
b := make([]byte, n)
_, err := io.ReadFull(r, b)
if err != nil {
return b, err
}
return b, nil
}
// ParsePkBin parses binary file representation of the ProvingKey into the ProvingKey struct
func ParsePkBin(f *os.File) (*types.Pk, error) {
o := 0
var pk types.Pk
r := bufio.NewReader(f)
b, err := readNBytes(r, 12)
if err != nil {
return nil, err
}
pk.NVars = int(binary.LittleEndian.Uint32(b[:4]))
pk.NPublic = int(binary.LittleEndian.Uint32(b[4:8]))
pk.DomainSize = int(binary.LittleEndian.Uint32(b[8:12]))
o += 12
b, err = readNBytes(r, 8)
if err != nil {
return nil, err
}
pPolsA := int(binary.LittleEndian.Uint32(b[:4]))
pPolsB := int(binary.LittleEndian.Uint32(b[4:8]))
o += 8
b, err = readNBytes(r, 20)
if err != nil {
return nil, err
}
pPointsA := int(binary.LittleEndian.Uint32(b[:4]))
pPointsB1 := int(binary.LittleEndian.Uint32(b[4:8]))
pPointsB2 := int(binary.LittleEndian.Uint32(b[8:12]))
pPointsC := int(binary.LittleEndian.Uint32(b[12:16]))
pPointsHExps := int(binary.LittleEndian.Uint32(b[16:20]))
o += 20
b, err = readNBytes(r, 64)
if err != nil {
return nil, err
}
pk.VkAlpha1 = new(bn256.G1)
_, err = pk.VkAlpha1.Unmarshal(fromMont1Q(b))
if err != nil {
return nil, err
}
b, err = readNBytes(r, 64)
if err != nil {
return nil, err
}
pk.VkBeta1 = new(bn256.G1)
_, err = pk.VkBeta1.Unmarshal(fromMont1Q(b))
if err != nil {
return nil, err
}
b, err = readNBytes(r, 64)
if err != nil {
return nil, err
}
pk.VkDelta1 = new(bn256.G1)
_, err = pk.VkDelta1.Unmarshal(fromMont1Q(b))
if err != nil {
return nil, err
}
b, err = readNBytes(r, 128)
if err != nil {
return nil, err
}
pk.VkBeta2 = new(bn256.G2)
_, err = pk.VkBeta2.Unmarshal(fromMont2Q(b))
if err != nil {
return nil, err
}
b, err = readNBytes(r, 128)
if err != nil {
return nil, err
}
pk.VkDelta2 = new(bn256.G2)
_, err = pk.VkDelta2.Unmarshal(fromMont2Q(b))
if err != nil {
return nil, err
}
o += 448
if o != pPolsA {
return nil, fmt.Errorf("Unexpected offset, expected: %v, actual: %v", pPolsA, o)
}
// PolsA
for i := 0; i < pk.NVars; i++ {
b, err = readNBytes(r, 4)
if err != nil {
return nil, err
}
keysLength := int(binary.LittleEndian.Uint32(b[:4]))
o += 4
polsMap := make(map[int]*big.Int)
for j := 0; j < keysLength; j++ {
bK, err := readNBytes(r, 4)
if err != nil {
return nil, err
}
key := int(binary.LittleEndian.Uint32(bK[:4]))
o += 4
b, err := readNBytes(r, 32)
if err != nil {
return nil, err
}
polsMap[key] = new(big.Int).SetBytes(fromMont1R(b[:32]))
o += 32
}
pk.PolsA = append(pk.PolsA, polsMap)
}
if o != pPolsB {
return nil, fmt.Errorf("Unexpected offset, expected: %v, actual: %v", pPolsB, o)
}
// PolsB
for i := 0; i < pk.NVars; i++ {
b, err = readNBytes(r, 4)
if err != nil {
return nil, err
}
keysLength := int(binary.LittleEndian.Uint32(b[:4]))
o += 4
polsMap := make(map[int]*big.Int)
for j := 0; j < keysLength; j++ {
bK, err := readNBytes(r, 4)
if err != nil {
return nil, err
}
key := int(binary.LittleEndian.Uint32(bK[:4]))
o += 4
b, err := readNBytes(r, 32)
if err != nil {
return nil, err
}
polsMap[key] = new(big.Int).SetBytes(fromMont1R(b[:32]))
o += 32
}
pk.PolsB = append(pk.PolsB, polsMap)
}
if o != pPointsA {
return nil, fmt.Errorf("Unexpected offset, expected: %v, actual: %v", pPointsA, o)
}
// A
for i := 0; i < pk.NVars; i++ {
b, err = readNBytes(r, 64)
if err != nil {
return nil, err
}
p1 := new(bn256.G1)
_, err = p1.Unmarshal(fromMont1Q(b))
if err != nil {
return nil, err
}
pk.A = append(pk.A, p1)
o += 64
}
if o != pPointsB1 {
return nil, fmt.Errorf("Unexpected offset, expected: %v, actual: %v", pPointsB1, o)
}
// B1
for i := 0; i < pk.NVars; i++ {
b, err = readNBytes(r, 64)
if err != nil {
return nil, err
}
p1 := new(bn256.G1)
_, err = p1.Unmarshal(fromMont1Q(b))
if err != nil {
return nil, err
}
pk.B1 = append(pk.B1, p1)
o += 64
}
if o != pPointsB2 {
return nil, fmt.Errorf("Unexpected offset, expected: %v, actual: %v", pPointsB2, o)
}
// B2
for i := 0; i < pk.NVars; i++ {
b, err = readNBytes(r, 128)
if err != nil {
return nil, err
}
p2 := new(bn256.G2)
_, err = p2.Unmarshal(fromMont2Q(b))
if err != nil {
return nil, err
}
pk.B2 = append(pk.B2, p2)
o += 128
}
if o != pPointsC {
return nil, fmt.Errorf("Unexpected offset, expected: %v, actual: %v", pPointsC, o)
}
// C
zb := make([]byte, 64)
z := new(bn256.G1)
_, err = z.Unmarshal(zb)
if err != nil {
return nil, err
}
pk.C = append(pk.C, z) // circom behaviour (3x null==["0", "0", "0"])
pk.C = append(pk.C, z)
pk.C = append(pk.C, z)
for i := pk.NPublic + 1; i < pk.NVars; i++ {
b, err = readNBytes(r, 64)
if err != nil {
return nil, err
}
p1 := new(bn256.G1)
_, err = p1.Unmarshal(fromMont1Q(b))
if err != nil {
return nil, err
}
pk.C = append(pk.C, p1)
o += 64
}
if o != pPointsHExps {
return nil, fmt.Errorf("Unexpected offset, expected: %v, actual: %v", pPointsHExps, o)
}
for i := 0; i < pk.DomainSize; i++ {
b, err = readNBytes(r, 64)
if err != nil {
return nil, err
}
p1 := new(bn256.G1)
_, err = p1.Unmarshal(fromMont1Q(b))
if err != nil {
return nil, err
}
pk.HExps = append(pk.HExps, p1)
}
return &pk, nil
}
func fromMont1Q(m []byte) []byte {
a := new(big.Int).SetBytes(swapEndianness(m[:32]))
b := new(big.Int).SetBytes(swapEndianness(m[32:64]))
x := coordFromMont(a, types.Q)
y := coordFromMont(b, types.Q)
if bytes.Equal(x.Bytes(), big.NewInt(1).Bytes()) {
x = big.NewInt(0)
}
if bytes.Equal(y.Bytes(), big.NewInt(1).Bytes()) {
y = big.NewInt(0)
}
xBytes := x.Bytes()
yBytes := y.Bytes()
if len(xBytes) != 32 {
xBytes = addZPadding(xBytes)
}
if len(yBytes) != 32 {
yBytes = addZPadding(yBytes)
}
var p []byte
p = append(p, xBytes...)
p = append(p, yBytes...)
return p
}
func fromMont2Q(m []byte) []byte {
a := new(big.Int).SetBytes(swapEndianness(m[:32]))
b := new(big.Int).SetBytes(swapEndianness(m[32:64]))
c := new(big.Int).SetBytes(swapEndianness(m[64:96]))
d := new(big.Int).SetBytes(swapEndianness(m[96:128]))
x := coordFromMont(a, types.Q)
y := coordFromMont(b, types.Q)
z := coordFromMont(c, types.Q)
t := coordFromMont(d, types.Q)
if bytes.Equal(x.Bytes(), big.NewInt(1).Bytes()) {
x = big.NewInt(0)
}
if bytes.Equal(y.Bytes(), big.NewInt(1).Bytes()) {
y = big.NewInt(0)
}
if bytes.Equal(z.Bytes(), big.NewInt(1).Bytes()) {
z = big.NewInt(0)
}
if bytes.Equal(t.Bytes(), big.NewInt(1).Bytes()) {
t = big.NewInt(0)
}
xBytes := x.Bytes()
yBytes := y.Bytes()
zBytes := z.Bytes()
tBytes := t.Bytes()
if len(xBytes) != 32 {
xBytes = addZPadding(xBytes)
}
if len(yBytes) != 32 {
yBytes = addZPadding(yBytes)
}
if len(zBytes) != 32 {
zBytes = addZPadding(zBytes)
}
if len(tBytes) != 32 {
tBytes = addZPadding(tBytes)
}
var p []byte
p = append(p, yBytes...) // swap
p = append(p, xBytes...)
p = append(p, tBytes...)
p = append(p, zBytes...)
return p
}
func fromMont1R(m []byte) []byte {
a := new(big.Int).SetBytes(swapEndianness(m[:32]))
x := coordFromMont(a, types.R)
return x.Bytes()
}
func fromMont2R(m []byte) []byte {
a := new(big.Int).SetBytes(swapEndianness(m[:32]))
b := new(big.Int).SetBytes(swapEndianness(m[32:64]))
c := new(big.Int).SetBytes(swapEndianness(m[64:96]))
d := new(big.Int).SetBytes(swapEndianness(m[96:128]))
x := coordFromMont(a, types.R)
y := coordFromMont(b, types.R)
z := coordFromMont(c, types.R)
t := coordFromMont(d, types.R)
var p []byte
p = append(p, y.Bytes()...) // swap
p = append(p, x.Bytes()...)
p = append(p, t.Bytes()...)
p = append(p, z.Bytes()...)
return p
}
func coordFromMont(u, q *big.Int) *big.Int {
return new(big.Int).Mod(
new(big.Int).Mul(
u,
new(big.Int).ModInverse(
new(big.Int).Lsh(big.NewInt(1), 256),
q,
),
),
q,
)
}

View File

@@ -1,9 +1,12 @@
package parsers
import (
"io/ioutil"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestParseArrayG1(t *testing.T) {
@@ -143,3 +146,113 @@ func TestParseArrayG2(t *testing.T) {
assert.Equal(t, "bn256.G2((1922d70c934543aa655ec3277f7fa10a25ec973a4f001a7c54ce4954b4916f8c, 14865e836947c42cf35b47d30e06535fff9dab319c4296e28afde368960671d5), (2f50fbe77925b0a9d718c9ab38638bafa7c65f43f0d09035e518df97ad294847, 177dfa1a3b8627faf0425d9511bcb4c6ca986ea05e3803b5c643c35b94a7e6fe))", a[3].String())
}
func testCircuitParseWitnessBin(t *testing.T, circuit string) {
witnessBinFile, err := os.Open("../testdata/" + circuit + "/witness.bin")
require.Nil(t, err)
defer witnessBinFile.Close()
witness, err := ParseWitnessBin(witnessBinFile)
require.Nil(t, err)
witnessJson, err := ioutil.ReadFile("../testdata/" + circuit + "/witness.json")
require.Nil(t, err)
w, err := ParseWitness(witnessJson)
require.Nil(t, err)
assert.Equal(t, len(w), len(witness))
assert.Equal(t, w[0], witness[0])
assert.Equal(t, w[1], witness[1])
assert.Equal(t, w[10], witness[10])
assert.Equal(t, w[len(w)-3], witness[len(w)-3])
assert.Equal(t, w[len(w)-2], witness[len(w)-2])
assert.Equal(t, w[len(w)-1], witness[len(w)-1])
}
func TestParseWitnessBin(t *testing.T) {
testCircuitParseWitnessBin(t, "circuit1k")
testCircuitParseWitnessBin(t, "circuit5k")
}
func TestProofSmartContractFormat(t *testing.T) {
proofJson, err := ioutil.ReadFile("../testdata/circuit1k/proof.json")
require.Nil(t, err)
proof, err := ParseProof(proofJson)
require.Nil(t, err)
pS := ProofToString(proof)
pSC := ProofToSmartContractFormat(proof)
assert.Nil(t, err)
assert.Equal(t, pS.A[0], pSC.A[0])
assert.Equal(t, pS.A[1], pSC.A[1])
assert.Equal(t, pS.B[0][0], pSC.B[0][1])
assert.Equal(t, pS.B[0][1], pSC.B[0][0])
assert.Equal(t, pS.B[1][0], pSC.B[1][1])
assert.Equal(t, pS.B[1][1], pSC.B[1][0])
assert.Equal(t, pS.C[0], pSC.C[0])
assert.Equal(t, pS.C[1], pSC.C[1])
assert.Equal(t, pS.Protocol, pSC.Protocol)
pSC2 := ProofStringToSmartContractFormat(pS)
assert.Equal(t, pSC, pSC2)
}
func testCircuitParsePkBin(t *testing.T, circuit string) {
pkBinFile, err := os.Open("../testdata/" + circuit + "/proving_key.bin")
require.Nil(t, err)
defer pkBinFile.Close()
pk, err := ParsePkBin(pkBinFile)
require.Nil(t, err)
pkJson, err := ioutil.ReadFile("../testdata/" + circuit + "/proving_key.json")
require.Nil(t, err)
pkJ, err := ParsePk(pkJson)
require.Nil(t, err)
assert.Equal(t, pkJ.NVars, pk.NVars)
assert.Equal(t, pkJ.NPublic, pk.NPublic)
assert.Equal(t, pkJ.DomainSize, pk.DomainSize)
assert.Equal(t, pkJ.VkAlpha1, pk.VkAlpha1)
assert.Equal(t, pkJ.VkBeta1, pk.VkBeta1)
assert.Equal(t, pkJ.VkDelta1, pk.VkDelta1)
assert.Equal(t, pkJ.VkDelta2, pk.VkDelta2)
assert.Equal(t, pkJ.PolsA, pk.PolsA)
assert.Equal(t, pkJ.PolsB, pk.PolsB)
assert.Equal(t, pkJ.A, pk.A)
assert.Equal(t, pkJ.B1, pk.B1)
assert.Equal(t, pkJ.B2, pk.B2)
assert.Equal(t, pkJ.C, pk.C)
assert.Equal(t, pkJ.HExps[:pkJ.DomainSize], pk.HExps[:pk.DomainSize]) // circom behaviour
}
func TestParsePkBin(t *testing.T) {
testCircuitParsePkBin(t, "circuit1k")
testCircuitParsePkBin(t, "circuit5k")
}
func benchmarkParsePk(b *testing.B, circuit string) {
pkJson, err := ioutil.ReadFile("../testdata/" + circuit + "/proving_key.json")
require.Nil(b, err)
pkBinFile, err := os.Open("../testdata/" + circuit + "/proving_key.bin")
require.Nil(b, err)
defer pkBinFile.Close()
b.Run("Parse Pk bin "+circuit, func(b *testing.B) {
for i := 0; i < b.N; i++ {
ParsePk(pkJson)
}
})
b.Run("Parse Pk json "+circuit, func(b *testing.B) {
for i := 0; i < b.N; i++ {
ParsePkBin(pkBinFile)
}
})
}
func BenchmarkParsePk(b *testing.B) {
benchmarkParsePk(b, "circuit1k")
benchmarkParsePk(b, "circuit5k")
// benchmarkParsePk(b, "circuit10k")
// benchmarkParsePk(b, "circuit20k")
}

View File

@@ -4,28 +4,46 @@ import (
"bytes"
"math/big"
bn256 "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare"
"github.com/iden3/go-circom-prover-verifier/types"
"github.com/iden3/go-iden3-crypto/ff"
)
func arrayOfZeroes(n int) []*big.Int {
var r []*big.Int
r := make([]*big.Int, n)
for i := 0; i < n; i++ {
r = append(r, new(big.Int).SetInt64(0))
r[i] = new(big.Int).SetInt64(0)
}
return r
return r[:]
}
func arrayOfZeroesE(n int) []*ff.Element {
var r []*ff.Element
r := make([]*ff.Element, n)
for i := 0; i < n; i++ {
r = append(r, ff.NewElement())
r[i] = ff.NewElement()
}
return r
return r[:]
}
func arrayOfZeroesG1(n int) []*bn256.G1 {
r := make([]*bn256.G1, n)
for i := 0; i < n; i++ {
r[i] = new(bn256.G1).ScalarBaseMult(big.NewInt(0))
}
return r[:]
}
func arrayOfZeroesG2(n int) []*bn256.G2 {
r := make([]*bn256.G2, n)
for i := 0; i < n; i++ {
r[i] = new(bn256.G2).ScalarBaseMult(big.NewInt(0))
}
return r[:]
}
func fAdd(a, b *big.Int) *big.Int {
ab := new(big.Int).Add(a, b)
return new(big.Int).Mod(ab, types.R)
return ab.Mod(ab, types.R)
}
func fSub(a, b *big.Int) *big.Int {
@@ -35,7 +53,7 @@ func fSub(a, b *big.Int) *big.Int {
func fMul(a, b *big.Int) *big.Int {
ab := new(big.Int).Mul(a, b)
return new(big.Int).Mod(ab, types.R)
return ab.Mod(ab, types.R)
}
func fDiv(a, b *big.Int) *big.Int {
@@ -62,7 +80,7 @@ func fExp(base *big.Int, e *big.Int) *big.Int {
res = fMul(res, exp)
}
exp = fMul(exp, exp)
rem = new(big.Int).Rsh(rem, 1)
rem.Rsh(rem, 1)
}
return res
}

463
prover/gextra.go Normal file
View File

@@ -0,0 +1,463 @@
package prover
import (
"math/big"
bn256 "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare"
cryptoConstants "github.com/iden3/go-iden3-crypto/constants"
)
type tableG1 struct {
data []*bn256.G1
}
func (t tableG1) getData() []*bn256.G1 {
return t.data
}
// Compute table of gsize elements as ::
// Table[0] = Inf
// Table[1] = a[0]
// Table[2] = a[1]
// Table[3] = a[0]+a[1]
// .....
// Table[(1<<gsize)-1] = a[0]+a[1]+...+a[gsize-1]
func (t *tableG1) newTableG1(a []*bn256.G1, gsize int, toaffine bool) {
// EC table
table := make([]*bn256.G1, 0)
// We need at least gsize elements. If not enough, fill with 0
aExt := make([]*bn256.G1, 0)
aExt = append(aExt, a...)
for i := len(a); i < gsize; i++ {
aExt = append(aExt, new(bn256.G1).ScalarBaseMult(big.NewInt(0)))
}
elG1 := new(bn256.G1).ScalarBaseMult(big.NewInt(0))
table = append(table, elG1)
lastPow2 := 1
nelems := 0
for i := 1; i < 1<<gsize; i++ {
elG1 := new(bn256.G1)
// if power of 2
if i&(i-1) == 0 {
lastPow2 = i
elG1.Set(aExt[nelems])
nelems++
} else {
elG1.Add(table[lastPow2], table[i-lastPow2])
// TODO bn256 doesn't export MakeAffine function. We need to fork repo
//table[i].MakeAffine()
}
table = append(table, elG1)
}
if toaffine {
for i := 0; i < len(table); i++ {
info := table[i].Marshal()
table[i].Unmarshal(info)
}
}
t.data = table
}
func (t tableG1) Marshal() []byte {
info := make([]byte, 0)
for _, el := range t.data {
info = append(info, el.Marshal()...)
}
return info
}
// Multiply scalar by precomputed table of G1 elements
func (t *tableG1) mulTableG1(k []*big.Int, qPrev *bn256.G1, gsize int) *bn256.G1 {
// We need at least gsize elements. If not enough, fill with 0
kExt := make([]*big.Int, 0)
kExt = append(kExt, k...)
for i := len(k); i < gsize; i++ {
kExt = append(kExt, new(big.Int).SetUint64(0))
}
Q := new(bn256.G1).ScalarBaseMult(big.NewInt(0))
msb := getMsb(kExt)
for i := msb - 1; i >= 0; i-- {
// TODO. bn256 doesn't export double operation. We will need to fork repo and export it
Q = new(bn256.G1).Add(Q, Q)
b := getBit(kExt, i)
if b != 0 {
// TODO. bn256 doesn't export mixed addition (Jacobian + Affine), which is more efficient.
Q.Add(Q, t.data[b])
}
}
if qPrev != nil {
return Q.Add(Q, qPrev)
}
return Q
}
// Multiply scalar by precomputed table of G1 elements without intermediate doubling
func mulTableNoDoubleG1(t []tableG1, k []*big.Int, qPrev *bn256.G1, gsize int) *bn256.G1 {
// We need at least gsize elements. If not enough, fill with 0
minNElems := len(t) * gsize
kExt := make([]*big.Int, 0)
kExt = append(kExt, k...)
for i := len(k); i < minNElems; i++ {
kExt = append(kExt, new(big.Int).SetUint64(0))
}
// Init Adders
nbitsQ := cryptoConstants.Q.BitLen()
Q := make([]*bn256.G1, nbitsQ)
for i := 0; i < nbitsQ; i++ {
Q[i] = new(bn256.G1).ScalarBaseMult(big.NewInt(0))
}
// Perform bitwise addition
for j := 0; j < len(t); j++ {
msb := getMsb(kExt[j*gsize : (j+1)*gsize])
for i := msb - 1; i >= 0; i-- {
b := getBit(kExt[j*gsize:(j+1)*gsize], i)
if b != 0 {
// TODO. bn256 doesn't export mixed addition (Jacobian + Affine), which is more efficient.
Q[i].Add(Q[i], t[j].data[b])
}
}
}
// Consolidate Addition
R := new(bn256.G1).Set(Q[nbitsQ-1])
for i := nbitsQ - 1; i > 0; i-- {
// TODO. bn256 doesn't export double operation. We will need to fork repo and export it
R = new(bn256.G1).Add(R, R)
R.Add(R, Q[i-1])
}
if qPrev != nil {
return R.Add(R, qPrev)
}
return R
}
// Compute tables within function. This solution should still be faster than std multiplication
// for gsize = 7
func scalarMultG1(a []*bn256.G1, k []*big.Int, qPrev *bn256.G1, gsize int) *bn256.G1 {
ntables := int((len(a) + gsize - 1) / gsize)
table := tableG1{}
Q := new(bn256.G1).ScalarBaseMult(new(big.Int))
for i := 0; i < ntables-1; i++ {
table.newTableG1(a[i*gsize:(i+1)*gsize], gsize, false)
Q = table.mulTableG1(k[i*gsize:(i+1)*gsize], Q, gsize)
}
table.newTableG1(a[(ntables-1)*gsize:], gsize, false)
Q = table.mulTableG1(k[(ntables-1)*gsize:], Q, gsize)
if qPrev != nil {
return Q.Add(Q, qPrev)
}
return Q
}
// Multiply scalar by precomputed table of G1 elements without intermediate doubling
func scalarMultNoDoubleG1(a []*bn256.G1, k []*big.Int, qPrev *bn256.G1, gsize int) *bn256.G1 {
ntables := int((len(a) + gsize - 1) / gsize)
table := tableG1{}
// We need at least gsize elements. If not enough, fill with 0
minNElems := ntables * gsize
kExt := make([]*big.Int, 0)
kExt = append(kExt, k...)
for i := len(k); i < minNElems; i++ {
kExt = append(kExt, new(big.Int).SetUint64(0))
}
// Init Adders
nbitsQ := cryptoConstants.Q.BitLen()
Q := make([]*bn256.G1, nbitsQ)
for i := 0; i < nbitsQ; i++ {
Q[i] = new(bn256.G1).ScalarBaseMult(big.NewInt(0))
}
// Perform bitwise addition
for j := 0; j < ntables-1; j++ {
table.newTableG1(a[j*gsize:(j+1)*gsize], gsize, false)
msb := getMsb(kExt[j*gsize : (j+1)*gsize])
for i := msb - 1; i >= 0; i-- {
b := getBit(kExt[j*gsize:(j+1)*gsize], i)
if b != 0 {
// TODO. bn256 doesn't export mixed addition (Jacobian + Affine), which is more efficient.
Q[i].Add(Q[i], table.data[b])
}
}
}
table.newTableG1(a[(ntables-1)*gsize:], gsize, false)
msb := getMsb(kExt[(ntables-1)*gsize:])
for i := msb - 1; i >= 0; i-- {
b := getBit(kExt[(ntables-1)*gsize:], i)
if b != 0 {
// TODO. bn256 doesn't export mixed addition (Jacobian + Affine), which is more efficient.
Q[i].Add(Q[i], table.data[b])
}
}
// Consolidate Addition
R := new(bn256.G1).Set(Q[nbitsQ-1])
for i := nbitsQ - 1; i > 0; i-- {
// TODO. bn256 doesn't export double operation. We will need to fork repo and export it
R = new(bn256.G1).Add(R, R)
R.Add(R, Q[i-1])
}
if qPrev != nil {
return R.Add(R, qPrev)
}
return R
}
/////
// TODO - How can avoid replicating code in G2?
//G2
type tableG2 struct {
data []*bn256.G2
}
func (t tableG2) getData() []*bn256.G2 {
return t.data
}
// Compute table of gsize elements as ::
// Table[0] = Inf
// Table[1] = a[0]
// Table[2] = a[1]
// Table[3] = a[0]+a[1]
// .....
// Table[(1<<gsize)-1] = a[0]+a[1]+...+a[gsize-1]
// TODO -> toaffine = True doesnt work. Problem with Marshal/Unmarshal
func (t *tableG2) newTableG2(a []*bn256.G2, gsize int, toaffine bool) {
// EC table
table := make([]*bn256.G2, 0)
// We need at least gsize elements. If not enough, fill with 0
aExt := make([]*bn256.G2, 0)
aExt = append(aExt, a...)
for i := len(a); i < gsize; i++ {
aExt = append(aExt, new(bn256.G2).ScalarBaseMult(big.NewInt(0)))
}
elG2 := new(bn256.G2).ScalarBaseMult(big.NewInt(0))
table = append(table, elG2)
lastPow2 := 1
nelems := 0
for i := 1; i < 1<<gsize; i++ {
elG2 := new(bn256.G2)
// if power of 2
if i&(i-1) == 0 {
lastPow2 = i
elG2.Set(aExt[nelems])
nelems++
} else {
elG2.Add(table[lastPow2], table[i-lastPow2])
// TODO bn256 doesn't export MakeAffine function. We need to fork repo
//table[i].MakeAffine()
}
table = append(table, elG2)
}
if toaffine {
for i := 0; i < len(table); i++ {
info := table[i].Marshal()
table[i].Unmarshal(info)
}
}
t.data = table
}
func (t tableG2) Marshal() []byte {
info := make([]byte, 0)
for _, el := range t.data {
info = append(info, el.Marshal()...)
}
return info
}
// Multiply scalar by precomputed table of G2 elements
func (t *tableG2) mulTableG2(k []*big.Int, qPrev *bn256.G2, gsize int) *bn256.G2 {
// We need at least gsize elements. If not enough, fill with 0
kExt := make([]*big.Int, 0)
kExt = append(kExt, k...)
for i := len(k); i < gsize; i++ {
kExt = append(kExt, new(big.Int).SetUint64(0))
}
Q := new(bn256.G2).ScalarBaseMult(big.NewInt(0))
msb := getMsb(kExt)
for i := msb - 1; i >= 0; i-- {
// TODO. bn256 doesn't export double operation. We will need to fork repo and export it
Q = new(bn256.G2).Add(Q, Q)
b := getBit(kExt, i)
if b != 0 {
// TODO. bn256 doesn't export mixed addition (Jacobian + Affine), which is more efficient.
Q.Add(Q, t.data[b])
}
}
if qPrev != nil {
return Q.Add(Q, qPrev)
}
return Q
}
// Multiply scalar by precomputed table of G2 elements without intermediate doubling
func mulTableNoDoubleG2(t []tableG2, k []*big.Int, qPrev *bn256.G2, gsize int) *bn256.G2 {
// We need at least gsize elements. If not enough, fill with 0
minNElems := len(t) * gsize
kExt := make([]*big.Int, 0)
kExt = append(kExt, k...)
for i := len(k); i < minNElems; i++ {
kExt = append(kExt, new(big.Int).SetUint64(0))
}
// Init Adders
nbitsQ := cryptoConstants.Q.BitLen()
Q := make([]*bn256.G2, nbitsQ)
for i := 0; i < nbitsQ; i++ {
Q[i] = new(bn256.G2).ScalarBaseMult(big.NewInt(0))
}
// Perform bitwise addition
for j := 0; j < len(t); j++ {
msb := getMsb(kExt[j*gsize : (j+1)*gsize])
for i := msb - 1; i >= 0; i-- {
b := getBit(kExt[j*gsize:(j+1)*gsize], i)
if b != 0 {
// TODO. bn256 doesn't export mixed addition (Jacobian + Affine), which is more efficient.
Q[i].Add(Q[i], t[j].data[b])
}
}
}
// Consolidate Addition
R := new(bn256.G2).Set(Q[nbitsQ-1])
for i := nbitsQ - 1; i > 0; i-- {
// TODO. bn256 doesn't export double operation. We will need to fork repo and export it
R = new(bn256.G2).Add(R, R)
R.Add(R, Q[i-1])
}
if qPrev != nil {
return R.Add(R, qPrev)
}
return R
}
// Compute tables within function. This solution should still be faster than std multiplication
// for gsize = 7
func scalarMultG2(a []*bn256.G2, k []*big.Int, qPrev *bn256.G2, gsize int) *bn256.G2 {
ntables := int((len(a) + gsize - 1) / gsize)
table := tableG2{}
Q := new(bn256.G2).ScalarBaseMult(new(big.Int))
for i := 0; i < ntables-1; i++ {
table.newTableG2(a[i*gsize:(i+1)*gsize], gsize, false)
Q = table.mulTableG2(k[i*gsize:(i+1)*gsize], Q, gsize)
}
table.newTableG2(a[(ntables-1)*gsize:], gsize, false)
Q = table.mulTableG2(k[(ntables-1)*gsize:], Q, gsize)
if qPrev != nil {
return Q.Add(Q, qPrev)
}
return Q
}
// Multiply scalar by precomputed table of G2 elements without intermediate doubling
func scalarMultNoDoubleG2(a []*bn256.G2, k []*big.Int, qPrev *bn256.G2, gsize int) *bn256.G2 {
ntables := int((len(a) + gsize - 1) / gsize)
table := tableG2{}
// We need at least gsize elements. If not enough, fill with 0
minNElems := ntables * gsize
kExt := make([]*big.Int, 0)
kExt = append(kExt, k...)
for i := len(k); i < minNElems; i++ {
kExt = append(kExt, new(big.Int).SetUint64(0))
}
// Init Adders
nbitsQ := cryptoConstants.Q.BitLen()
Q := make([]*bn256.G2, nbitsQ)
for i := 0; i < nbitsQ; i++ {
Q[i] = new(bn256.G2).ScalarBaseMult(big.NewInt(0))
}
// Perform bitwise addition
for j := 0; j < ntables-1; j++ {
table.newTableG2(a[j*gsize:(j+1)*gsize], gsize, false)
msb := getMsb(kExt[j*gsize : (j+1)*gsize])
for i := msb - 1; i >= 0; i-- {
b := getBit(kExt[j*gsize:(j+1)*gsize], i)
if b != 0 {
// TODO. bn256 doesn't export mixed addition (Jacobian + Affine), which is more efficient.
Q[i].Add(Q[i], table.data[b])
}
}
}
table.newTableG2(a[(ntables-1)*gsize:], gsize, false)
msb := getMsb(kExt[(ntables-1)*gsize:])
for i := msb - 1; i >= 0; i-- {
b := getBit(kExt[(ntables-1)*gsize:], i)
if b != 0 {
// TODO. bn256 doesn't export mixed addition (Jacobian + Affine), which is more efficient.
Q[i].Add(Q[i], table.data[b])
}
}
// Consolidate Addition
R := new(bn256.G2).Set(Q[nbitsQ-1])
for i := nbitsQ - 1; i > 0; i-- {
// TODO. bn256 doesn't export double operation. We will need to fork repo and export it
R = new(bn256.G2).Add(R, R)
R.Add(R, Q[i-1])
}
if qPrev != nil {
return R.Add(R, qPrev)
}
return R
}
// Return most significant bit position in a group of Big Integers
func getMsb(k []*big.Int) int {
msb := 0
for _, el := range k {
tmpMsb := el.BitLen()
if tmpMsb > msb {
msb = tmpMsb
}
}
return msb
}
// Return ith bit in group of Big Integers
func getBit(k []*big.Int, i int) uint {
tableIdx := uint(0)
for idx, el := range k {
b := el.Bit(i)
tableIdx += (b << idx)
}
return tableIdx
}

163
prover/gextra_test.go Normal file
View File

@@ -0,0 +1,163 @@
package prover
import (
"bytes"
"crypto/rand"
"fmt"
"math/big"
"testing"
"time"
bn256 "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare"
)
const (
N1 = 5000
N2 = 5000
)
func randomBigIntArray(n int) []*big.Int {
var p []*big.Int
for i := 0; i < n; i++ {
pi := randBI()
p = append(p, pi)
}
return p
}
func randomG1Array(n int) []*bn256.G1 {
arrayG1 := make([]*bn256.G1, n)
for i := 0; i < n; i++ {
_, arrayG1[i], _ = bn256.RandomG1(rand.Reader)
}
return arrayG1
}
func randomG2Array(n int) []*bn256.G2 {
arrayG2 := make([]*bn256.G2, n)
for i := 0; i < n; i++ {
_, arrayG2[i], _ = bn256.RandomG2(rand.Reader)
}
return arrayG2
}
func TestTableG1(t *testing.T) {
n := N1
// init scalar
var arrayW = randomBigIntArray(n)
// init G1 array
var arrayG1 = randomG1Array(n)
beforeT := time.Now()
Q1 := new(bn256.G1).ScalarBaseMult(new(big.Int))
for i := 0; i < n; i++ {
Q1.Add(Q1, new(bn256.G1).ScalarMult(arrayG1[i], arrayW[i]))
}
fmt.Println("Std. Mult. time elapsed:", time.Since(beforeT))
for gsize := 2; gsize < 10; gsize++ {
ntables := int((n + gsize - 1) / gsize)
table := make([]tableG1, ntables)
for i := 0; i < ntables-1; i++ {
table[i].newTableG1(arrayG1[i*gsize:(i+1)*gsize], gsize, true)
}
table[ntables-1].newTableG1(arrayG1[(ntables-1)*gsize:], gsize, true)
beforeT = time.Now()
Q2 := new(bn256.G1).ScalarBaseMult(new(big.Int))
for i := 0; i < ntables-1; i++ {
Q2 = table[i].mulTableG1(arrayW[i*gsize:(i+1)*gsize], Q2, gsize)
}
Q2 = table[ntables-1].mulTableG1(arrayW[(ntables-1)*gsize:], Q2, gsize)
fmt.Printf("Gsize : %d, TMult time elapsed: %s\n", gsize, time.Since(beforeT))
beforeT = time.Now()
Q3 := scalarMultG1(arrayG1, arrayW, nil, gsize)
fmt.Printf("Gsize : %d, TMult time elapsed (inc table comp): %s\n", gsize, time.Since(beforeT))
beforeT = time.Now()
Q4 := mulTableNoDoubleG1(table, arrayW, nil, gsize)
fmt.Printf("Gsize : %d, TMultNoDouble time elapsed: %s\n", gsize, time.Since(beforeT))
beforeT = time.Now()
Q5 := scalarMultNoDoubleG1(arrayG1, arrayW, nil, gsize)
fmt.Printf("Gsize : %d, TMultNoDouble time elapsed (inc table comp): %s\n", gsize, time.Since(beforeT))
if bytes.Compare(Q1.Marshal(), Q2.Marshal()) != 0 {
t.Error("Error in TMult")
}
if bytes.Compare(Q1.Marshal(), Q3.Marshal()) != 0 {
t.Error("Error in TMult with table comp")
}
if bytes.Compare(Q1.Marshal(), Q4.Marshal()) != 0 {
t.Error("Error in TMultNoDouble")
}
if bytes.Compare(Q1.Marshal(), Q5.Marshal()) != 0 {
t.Error("Error in TMultNoDoublee with table comp")
}
}
}
func TestTableG2(t *testing.T) {
n := N2
// init scalar
var arrayW = randomBigIntArray(n)
// init G2 array
var arrayG2 = randomG2Array(n)
beforeT := time.Now()
Q1 := new(bn256.G2).ScalarBaseMult(new(big.Int))
for i := 0; i < n; i++ {
Q1.Add(Q1, new(bn256.G2).ScalarMult(arrayG2[i], arrayW[i]))
}
fmt.Println("Std. Mult. time elapsed:", time.Since(beforeT))
for gsize := 2; gsize < 10; gsize++ {
ntables := int((n + gsize - 1) / gsize)
table := make([]tableG2, ntables)
for i := 0; i < ntables-1; i++ {
table[i].newTableG2(arrayG2[i*gsize:(i+1)*gsize], gsize, false)
}
table[ntables-1].newTableG2(arrayG2[(ntables-1)*gsize:], gsize, false)
beforeT = time.Now()
Q2 := new(bn256.G2).ScalarBaseMult(new(big.Int))
for i := 0; i < ntables-1; i++ {
Q2 = table[i].mulTableG2(arrayW[i*gsize:(i+1)*gsize], Q2, gsize)
}
Q2 = table[ntables-1].mulTableG2(arrayW[(ntables-1)*gsize:], Q2, gsize)
fmt.Printf("Gsize : %d, TMult time elapsed: %s\n", gsize, time.Since(beforeT))
beforeT = time.Now()
Q3 := scalarMultG2(arrayG2, arrayW, nil, gsize)
fmt.Printf("Gsize : %d, TMult time elapsed (inc table comp): %s\n", gsize, time.Since(beforeT))
beforeT = time.Now()
Q4 := mulTableNoDoubleG2(table, arrayW, nil, gsize)
fmt.Printf("Gsize : %d, TMultNoDouble time elapsed: %s\n", gsize, time.Since(beforeT))
beforeT = time.Now()
Q5 := scalarMultNoDoubleG2(arrayG2, arrayW, nil, gsize)
fmt.Printf("Gsize : %d, TMultNoDouble time elapsed (inc table comp): %s\n", gsize, time.Since(beforeT))
if bytes.Compare(Q1.Marshal(), Q2.Marshal()) != 0 {
t.Error("Error in TMult")
}
if bytes.Compare(Q1.Marshal(), Q3.Marshal()) != 0 {
t.Error("Error in TMult with table comp")
}
if bytes.Compare(Q1.Marshal(), Q4.Marshal()) != 0 {
t.Error("Error in TMultNoDouble")
}
if bytes.Compare(Q1.Marshal(), Q5.Marshal()) != 0 {
t.Error("Error in TMultNoDoublee with table comp")
}
}
}

View File

@@ -4,12 +4,13 @@ import (
"crypto/rand"
"math"
"math/big"
"runtime"
"sync"
bn256 "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare"
"github.com/iden3/go-circom-prover-verifier/types"
"github.com/iden3/go-iden3-crypto/ff"
"github.com/iden3/go-iden3-crypto/utils"
//"fmt"
)
// Proof is the data structure of the Groth16 zkSNARK proof
@@ -42,6 +43,11 @@ type Pk struct {
// Witness contains the witness
type Witness []*big.Int
// Group Size
const (
GSIZE = 6
)
func randBigInt() (*big.Int, error) {
maxbits := types.R.BitLen()
b := make([]byte, (maxbits/8)-1)
@@ -68,66 +74,92 @@ func GenerateProof(pk *types.Pk, w types.Witness) (*types.Proof, []*big.Int, err
return nil, nil, err
}
proof.A = new(bn256.G1).ScalarBaseMult(big.NewInt(0))
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))
// BEGIN PAR
numcpu := runtime.NumCPU()
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]))
proofA := arrayOfZeroesG1(numcpu)
proofB := arrayOfZeroesG2(numcpu)
proofC := arrayOfZeroesG1(numcpu)
proofBG1 := arrayOfZeroesG1(numcpu)
gsize := GSIZE
var wg1 sync.WaitGroup
wg1.Add(numcpu)
for _cpu, _ranges := range ranges(pk.NVars, numcpu) {
// split 1
go func(cpu int, ranges [2]int) {
proofA[cpu] = scalarMultNoDoubleG1(pk.A[ranges[0]:ranges[1]],
w[ranges[0]:ranges[1]],
proofA[cpu],
gsize)
proofB[cpu] = scalarMultNoDoubleG2(pk.B2[ranges[0]:ranges[1]],
w[ranges[0]:ranges[1]],
proofB[cpu],
gsize)
proofBG1[cpu] = scalarMultNoDoubleG1(pk.B1[ranges[0]:ranges[1]],
w[ranges[0]:ranges[1]],
proofBG1[cpu],
gsize)
minLim := pk.NPublic + 1
if ranges[0] > pk.NPublic+1 {
minLim = ranges[0]
}
wg.Done()
}()
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]))
if ranges[1] > pk.NPublic+1 {
proofC[cpu] = scalarMultNoDoubleG1(pk.C[minLim:ranges[1]],
w[minLim:ranges[1]],
proofC[cpu],
gsize)
}
wg.Done()
}()
go func() {
for i := 0; i < pk.NVars; i++ {
proofBG1 = new(bn256.G1).Add(proofBG1, new(bn256.G1).ScalarMult(pk.B1[i], w[i]))
wg1.Done()
}(_cpu, _ranges)
}
wg.Done()
}()
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]))
wg1.Wait()
// join 1
for cpu := 1; cpu < numcpu; cpu++ {
proofA[0].Add(proofA[0], proofA[cpu])
proofB[0].Add(proofB[0], proofB[cpu])
proofC[0].Add(proofC[0], proofC[cpu])
proofBG1[0].Add(proofBG1[0], proofBG1[cpu])
}
wg.Done()
}()
wg.Wait()
proof.A = proofA[0]
proof.B = proofB[0]
proof.C = proofC[0]
// END PAR
h := calculateH(pk, w)
proof.A.Add(proof.A, pk.VkAlpha1)
proof.A.Add(proof.A, new(bn256.G1).ScalarMult(pk.VkDelta1, r))
proof.B.Add(proof.B, pk.VkBeta2)
proof.B.Add(proof.B, new(bn256.G2).ScalarMult(pk.VkDelta2, s))
proofBG1[0].Add(proofBG1[0], pk.VkBeta1)
proofBG1[0].Add(proofBG1[0], new(bn256.G1).ScalarMult(pk.VkDelta1, s))
proofC = arrayOfZeroesG1(numcpu)
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))
proof.B = new(bn256.G2).Add(proof.B, pk.VkBeta2)
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))
wg2.Add(numcpu)
for _cpu, _ranges := range ranges(len(h), numcpu) {
// split 2
go func(cpu int, ranges [2]int) {
proofC[cpu] = scalarMultNoDoubleG1(pk.HExps[ranges[0]:ranges[1]],
h[ranges[0]:ranges[1]],
proofC[cpu],
gsize)
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]))
}(_cpu, _ranges)
}
wg2.Done()
}()
wg2.Wait()
// join 2
for cpu := 1; cpu < numcpu; cpu++ {
proofC[0].Add(proofC[0], proofC[cpu])
}
proof.C.Add(proof.C, proofC[0])
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))
rsneg := new(big.Int).Mod(new(big.Int).Neg(new(big.Int).Mul(r, s)), types.R) // fAdd & fMul
proof.C = new(bn256.G1).Add(proof.C, new(bn256.G1).ScalarMult(pk.VkDelta1, rsneg))
proof.C.Add(proof.C, new(bn256.G1).ScalarMult(proof.A, s))
proof.C.Add(proof.C, new(bn256.G1).ScalarMult(proofBG1[0], r))
rsneg := new(big.Int).Mod(new(big.Int).Neg(new(big.Int).Mul(r, s)), types.R)
proof.C.Add(proof.C, new(bn256.G1).ScalarMult(pk.VkDelta1, rsneg))
pubSignals := w[1 : pk.NPublic+1]
@@ -139,14 +171,27 @@ func calculateH(pk *types.Pk, w types.Witness) []*big.Int {
polAT := arrayOfZeroes(m)
polBT := arrayOfZeroes(m)
numcpu := runtime.NumCPU()
var wg1 sync.WaitGroup
wg1.Add(2)
go func() {
for i := 0; i < pk.NVars; i++ {
for j := range pk.PolsA[i] {
polAT[j] = fAdd(polAT[j], fMul(w[i], pk.PolsA[i][j]))
}
}
wg1.Done()
}()
go func() {
for i := 0; i < pk.NVars; i++ {
for j := range pk.PolsB[i] {
polBT[j] = fAdd(polBT[j], fMul(w[i], pk.PolsB[i][j]))
}
}
wg1.Done()
}()
wg1.Wait()
polATe := utils.BigIntArrayToElementArray(polAT)
polBTe := utils.BigIntArrayToElementArray(polBT)
@@ -156,22 +201,49 @@ func calculateH(pk *types.Pk, w types.Witness) []*big.Int {
r := int(math.Log2(float64(m))) + 1
roots := newRootsT()
roots.setRoots(r)
for i := 0; i < len(polASe); i++ {
polASe[i] = ff.NewElement().Mul(polASe[i], roots.roots[r][i])
polBSe[i] = ff.NewElement().Mul(polBSe[i], roots.roots[r][i])
var wg2 sync.WaitGroup
wg2.Add(numcpu)
for _cpu, _ranges := range ranges(len(polASe), numcpu) {
go func(cpu int, ranges [2]int) {
for i := ranges[0]; i < ranges[1]; i++ {
polASe[i].Mul(polASe[i], roots.roots[r][i])
polBSe[i].Mul(polBSe[i], roots.roots[r][i])
}
wg2.Done()
}(_cpu, _ranges)
}
wg2.Wait()
polATodd := fft(polASe)
polBTodd := fft(polBSe)
polABT := arrayOfZeroesE(len(polASe) * 2)
for i := 0; i < len(polASe); i++ {
polABT[2*i] = ff.NewElement().Mul(polATe[i], polBTe[i])
polABT[2*i+1] = ff.NewElement().Mul(polATodd[i], polBTodd[i])
var wg3 sync.WaitGroup
wg3.Add(numcpu)
for _cpu, _ranges := range ranges(len(polASe), numcpu) {
go func(cpu int, ranges [2]int) {
for i := ranges[0]; i < ranges[1]; i++ {
polABT[2*i].Mul(polATe[i], polBTe[i])
polABT[2*i+1].Mul(polATodd[i], polBTodd[i])
}
wg3.Done()
}(_cpu, _ranges)
}
wg3.Wait()
hSeFull := ifft(polABT)
hSe := hSeFull[m:]
return utils.ElementArrayToBigIntArray(hSe)
}
func ranges(n, parts int) [][2]int {
s := make([][2]int, parts)
p := float64(n) / float64(parts)
for i := 0; i < parts; i++ {
a, b := int(float64(i)*p), int(float64(i+1)*p)
s[i] = [2]int{a, b}
}
return s
}

View File

@@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"testing"
"time"
@@ -21,20 +22,33 @@ func TestCircuitsGenerateProof(t *testing.T) {
}
func testCircuitGenerateProof(t *testing.T, circuit string) {
provingKeyJson, err := ioutil.ReadFile("../testdata/" + circuit + "/proving_key.json")
// using json provingKey file
// 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/" + circuit + "/witness.json")
// require.Nil(t, err)
// w, err := parsers.ParseWitness(witnessJson)
// require.Nil(t, err)
// using bin provingKey file
pkBinFile, err := os.Open("../testdata/" + circuit + "/proving_key.bin")
require.Nil(t, err)
pk, err := parsers.ParsePk(provingKeyJson)
defer pkBinFile.Close()
pk, err := parsers.ParsePkBin(pkBinFile)
require.Nil(t, err)
witnessJson, err := ioutil.ReadFile("../testdata/" + circuit + "/witness.json")
witnessBinFile, err := os.Open("../testdata/" + circuit + "/witness.bin")
require.Nil(t, err)
w, err := parsers.ParseWitness(witnessJson)
defer witnessBinFile.Close()
w, err := parsers.ParseWitnessBin(witnessBinFile)
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))
fmt.Println("proof generation time for "+circuit+" elapsed:", time.Since(beforeT))
proofStr, err := parsers.ProofToJson(proof)
assert.Nil(t, err)
@@ -61,12 +75,12 @@ func testCircuitGenerateProof(t *testing.T, circuit string) {
func BenchmarkGenerateProof(b *testing.B) {
// benchmark with a circuit of 10000 constraints
provingKeyJson, err := ioutil.ReadFile("../testdata/circuit1/proving_key.json")
provingKeyJson, err := ioutil.ReadFile("../testdata/circuit5k/proving_key.json")
require.Nil(b, err)
pk, err := parsers.ParsePk(provingKeyJson)
require.Nil(b, err)
witnessJson, err := ioutil.ReadFile("../testdata/circuit1/witness.json")
witnessJson, err := ioutil.ReadFile("../testdata/circuit5k/witness.json")
require.Nil(b, err)
w, err := parsers.ParseWitness(witnessJson)
require.Nil(b, err)

49
prover/tables.md Normal file
View File

@@ -0,0 +1,49 @@
# Tables Pre-calculation
The most time consuming part of a ZKSnark proof calculation is the scalar multiplication of elliptic curve points. Direct mechanism accumulates each multiplication. However, prover only needs the total accumulation.
There are two potential improvements to the naive approach:
1. Apply Strauss-Shamir method (https://stackoverflow.com/questions/50993471/ec-scalar-multiplication-with-strauss-shamir-method).
2. Leave the doubling operation for the last step
Both options can be combined.
In the following table, we show the results of using the naive method, Srauss-Shamir and Strauss-Shamir + No doubling. These last two options are repeated for different table grouping order.
There are 50000 G1 Elliptical Curve Points, and the scalars are 254 bits (BN256 curve).
There may be some concern on the additional size of the tables since they need to be loaded into a smartphone during the proof, and the time required to load these tables may exceed the benefits. If this is a problem, another althernative is to compute the tables during the proof itself. Depending on the Group Size, timing may be better than the naive approach.
| Algorithm (G1) | GS 2 | GS 3 | GS 4 | GS 5 | GS 6 | GS 7 | GS 8 | GS 9 |
|---|---|---|--|---|---|---|---|---|
| Naive | 6.63s | - | - | - | - | - | - | - |
| Strauss | 13.16s | 9.03s | 6.95s | 5.61s | 4.91s | 4.26s | 3.88s | 3.54 s |
| Strauss + Table Computation | 16.13s | 11.32s | 8.47s | 7.10s | 6.2s | 5.94s | 6.01s | 6.69s |
| No Doubling | 3.74s | 3.00s | 2.38s | 1.96s | 1.79s | 1.54s | 1.50s | 1.44s|
| No Doubling + Table Computation | 6.83s | 5.1s | 4.16s | 3.52s| 3.22s | 3.21s | 3.57s | 4.56s |
There are 5000 G2 Elliptical Curve Points, and the scalars are 254 bits (BN256 curve).
| Algorithm (G2) | GS 2 | GS 3 | GS 4 | GS 5 | GS 6 | GS 7 | GS 8 | GS 9 |
|---|---|---|--|---|---|---|---|---|
| Naive | 3.55s | | | | | | | |
| Strauss | 3.55s | 2.54s | 1.96s | 1.58s | 1.38s | 1.20s | 1.03s | 937ms |
| Strauss + Table Computation | 3.59s | 2.58s | 2.04s | 1.71s | 1.51s | 1.46s | 1.51s | 1.82s |
| No Doubling | 1.49s | 1.16s | 952ms | 719ms | 661ms | 548ms | 506ms| 444ms |
| No Doubling + Table Computation | 1.55s | 1.21s | 984ms | 841ms | 826ms | 847ms | 1.03s | 1.39s |
| GS | Extra Disk Space per Constraint (G1)|
|----|--------|
| 2 | 64 B |
| 3 | 106 B |
| 4 | 192 B |
| 5 | 346 B |
| 6 | 618 B |
| 7 | 1106 B |
| 8 | 1984 B |
| 9 | 3577 B |
| N | 2^(N+6)/N - 64 B |
Extra disk space per constraint in G2 is twice the requirements for G1

1
testdata/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
node_modules

View File

@@ -1,29 +1,31 @@
#!/bin/sh
npm install
compile_and_ts_and_witness() {
echo $(date +"%T") "circom circuit.circom --r1cs --wasm --sym"
itime="$(date -u +%s)"
circom circuit.circom --r1cs --wasm --sym
../node_modules/.bin/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
../node_modules/.bin/snarkjs info -r circuit.r1cs
echo $(date +"%T") "snarkjs setup"
itime="$(date -u +%s)"
snarkjs setup
../node_modules/.bin/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
../node_modules/.bin/snarkjs calculatewitness --wasm circuit.wasm --input inputs.json --witness witness.json
echo $(date +"%T") "snarkjs generateverifier"
itime="$(date -u +%s)"
snarkjs generateverifier
../node_modules/.bin/snarkjs generateverifier
echo " ($(($(date -u +%s)-$itime))s)"
echo $(date +"%T") "generateverifier generated"
}
@@ -40,3 +42,22 @@ compile_and_ts_and_witness
# echo "compile & trustesetup for circuit20k"
# cd ../circuit20k
# compile_and_ts_and_witness
cd ../
echo "convert witness & pk of circuit1k to bin"
node node_modules/wasmsnark/tools/buildwitness.js -i circuit1k/witness.json -o circuit1k/witness.bin
node node_modules/wasmsnark/tools/buildpkey.js -i circuit1k/proving_key.json -o circuit1k/proving_key.bin
echo "convert witness & pk of circuit5k to bin"
node node_modules/wasmsnark/tools/buildwitness.js -i circuit5k/witness.json -o circuit5k/witness.bin
node node_modules/wasmsnark/tools/buildpkey.js -i circuit5k/proving_key.json -o circuit5k/proving_key.bin
# echo "convert witness & pk of circuit10k to bin"
# node node_modules/wasmsnark/tools/buildwitness.js -i circuit10k/witness.json -o circuit10k/witness.bin
# node node_modules/wasmsnark/tools/buildpkey.js -i circuit10k/proving_key.json -o circuit10k/proving_key.bin
#
# echo "convert witness & pk of circuit20k to bin"
# node node_modules/wasmsnark/tools/buildwitness.js -i circuit20k/witness.json -o circuit20k/witness.bin
# node node_modules/wasmsnark/tools/buildpkey.js -i circuit20k/proving_key.json -o circuit20k/proving_key.bin

923
testdata/package-lock.json generated vendored Normal file
View File

@@ -0,0 +1,923 @@
{
"name": "binformat",
"version": "0.0.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@types/color-name": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ=="
},
"ansi-regex": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
},
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"requires": {
"color-convert": "^1.9.0"
}
},
"assertion-error": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw=="
},
"async": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
"integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0="
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"big-integer": {
"version": "1.6.48",
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz",
"integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w=="
},
"blakejs": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.1.0.tgz",
"integrity": "sha1-ad+S75U6qIylGjLfarHFShVfx6U="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
},
"chai": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz",
"integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==",
"requires": {
"assertion-error": "^1.1.0",
"check-error": "^1.0.2",
"deep-eql": "^3.0.1",
"get-func-name": "^2.0.0",
"pathval": "^1.1.0",
"type-detect": "^4.0.5"
}
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"check-error": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
"integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII="
},
"circom": {
"version": "0.5.11",
"resolved": "https://registry.npmjs.org/circom/-/circom-0.5.11.tgz",
"integrity": "sha512-rX56jFdLSZx7o9bhVIVQhe+AQYSKapMc9Lrbg27MVTPPSaCZi2T3gbR3wsAISPGp2aH50kZtTvIzvo5O7XcW1Q==",
"requires": {
"chai": "^4.2.0",
"circom_runtime": "0.0.6",
"fastfile": "0.0.1",
"ffiasm": "0.0.2",
"ffjavascript": "0.1.2",
"ffwasm": "0.0.7",
"fnv-plus": "^1.3.1",
"r1csfile": "0.0.5",
"tmp-promise": "^2.0.2",
"wasmbuilder": "0.0.10"
}
},
"circom_runtime": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.0.6.tgz",
"integrity": "sha512-o0T5MuWzxnxinWG3+CygS/kZouoP+z5ZrufUwqKJy3gsVFJhkbqMpfKmcBGjhExB3uatA7cKyOiRAOLOz5+t5w==",
"requires": {
"ffjavascript": "0.1.0",
"fnv-plus": "^1.3.1"
},
"dependencies": {
"ffjavascript": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.1.0.tgz",
"integrity": "sha512-dmKlUasSfvUcxBm8nCSKl2x7EFJsXA7OVP8XLFA03T2+6mAc3IiVLC2ambEVOcMOhyhl0vJfVZjM9f9d38D1rw==",
"requires": {
"big-integer": "^1.6.48"
}
}
}
},
"cliui": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
"requires": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^6.2.0"
}
},
"code-point-at": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
},
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"requires": {
"color-name": "1.1.3"
}
},
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"cross-spawn": {
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
"integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
"requires": {
"nice-try": "^1.0.4",
"path-key": "^2.0.1",
"semver": "^5.5.0",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
}
},
"decamelize": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
},
"deep-eql": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
"integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
"requires": {
"type-detect": "^4.0.0"
}
},
"ejs": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.2.tgz",
"integrity": "sha512-zFuywxrAWtX5Mk2KAuoJNkXXbfezpNA0v7i+YC971QORguPekpjpAgeOv99YWSdKXwj7JxI2QAWDeDkE8fWtXw==",
"requires": {
"jake": "^10.6.1"
}
},
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
},
"end-of-stream": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
"requires": {
"once": "^1.4.0"
}
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"execa": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
"integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
"requires": {
"cross-spawn": "^6.0.0",
"get-stream": "^4.0.0",
"is-stream": "^1.1.0",
"npm-run-path": "^2.0.0",
"p-finally": "^1.0.0",
"signal-exit": "^3.0.0",
"strip-eof": "^1.0.0"
}
},
"fastfile": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/fastfile/-/fastfile-0.0.1.tgz",
"integrity": "sha512-Fk8PWafGWGEUw7oPq/dJen92ASxknCEy4ZC8n4VEvSwCp/jcReyEmVoWsRIWTf+IvAp2MzvFi54vOPeK2LQZtQ=="
},
"ffiasm": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/ffiasm/-/ffiasm-0.0.2.tgz",
"integrity": "sha512-o/CL7F4IodB7eRHCOQL1SrqN2DIPHrQbEwjPY7NIyeBRdnB3G0xo6b6Mj44SKiWFnvpQMb3n4N7acjD3vv4NVQ==",
"requires": {
"big-integer": "^1.6.48",
"ejs": "^3.0.1",
"yargs": "^15.3.1"
}
},
"ffjavascript": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.1.2.tgz",
"integrity": "sha512-zB1dhgBjJlvyk2VQIQzFSpUJmanYQYDR/Fo1KhZnaNW5chMFJT55qz0dx1LMKrAklBbidKzz2/C7dgibxQF94g==",
"requires": {
"big-integer": "^1.6.48"
}
},
"ffwasm": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/ffwasm/-/ffwasm-0.0.7.tgz",
"integrity": "sha512-17cTLzv7HHAKqZbX8MvHxjSrR0yDdn1sh4TVsTbAvO9e6klhFicnyoVXc/sCuViV/M8g65sCmVrAmoPCZp1YkQ==",
"requires": {
"big-integer": "^1.6.48",
"wasmbuilder": "0.0.10"
}
},
"filelist": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.1.tgz",
"integrity": "sha512-8zSK6Nu0DQIC08mUC46sWGXi+q3GGpKydAG36k+JDba6VRpkevvOWUW5a/PhShij4+vHT9M+ghgG7eM+a9JDUQ==",
"requires": {
"minimatch": "^3.0.4"
}
},
"find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"requires": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
}
},
"fnv-plus": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/fnv-plus/-/fnv-plus-1.3.1.tgz",
"integrity": "sha512-Gz1EvfOneuFfk4yG458dJ3TLJ7gV19q3OM/vVvvHf7eT02Hm1DleB4edsia6ahbKgAYxO9gvyQ1ioWZR+a00Yw=="
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
},
"get-func-name": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
"integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE="
},
"get-stream": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
"integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
"requires": {
"pump": "^3.0.0"
}
},
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"invert-kv": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz",
"integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA=="
},
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
},
"is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
},
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
},
"jake": {
"version": "10.6.1",
"resolved": "https://registry.npmjs.org/jake/-/jake-10.6.1.tgz",
"integrity": "sha512-pHUK3+V0BjOb1XSi95rbBksrMdIqLVC9bJqDnshVyleYsET3H0XAq+3VB2E3notcYvv4wRdRHn13p7vobG+wfQ==",
"requires": {
"async": "0.9.x",
"chalk": "^2.4.2",
"filelist": "^1.0.1",
"minimatch": "^3.0.4"
}
},
"keccak": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.0.tgz",
"integrity": "sha512-/4h4FIfFEpTEuySXi/nVFM5rqSKPnnhI7cL4K3MFSwoI3VyM7AhPSq3SsysARtnEBEeIKMBUWD8cTh9nHE8AkA==",
"requires": {
"node-addon-api": "^2.0.0",
"node-gyp-build": "^4.2.0"
}
},
"lcid": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
"integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
"requires": {
"invert-kv": "^2.0.0"
}
},
"locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"requires": {
"p-locate": "^4.1.0"
}
},
"map-age-cleaner": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
"integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
"requires": {
"p-defer": "^1.0.0"
}
},
"mem": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz",
"integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==",
"requires": {
"map-age-cleaner": "^0.1.1",
"mimic-fn": "^2.0.0",
"p-is-promise": "^2.0.0"
}
},
"mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
},
"node-addon-api": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.0.tgz",
"integrity": "sha512-ASCL5U13as7HhOExbT6OlWJJUV/lLzL2voOSP1UVehpRD8FbSrSDjfScK/KwAvVTI5AS6r4VwbOMlIqtvRidnA=="
},
"node-gyp-build": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.2.tgz",
"integrity": "sha512-Lqh7mrByWCM8Cf9UPqpeoVBBo5Ugx+RKu885GAzmLBVYjeywScxHXPGLa4JfYNZmcNGwzR0Glu5/9GaQZMFqyA=="
},
"npm-run-path": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
"integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
"requires": {
"path-key": "^2.0.0"
}
},
"number-is-nan": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1"
}
},
"os-locale": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz",
"integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
"requires": {
"execa": "^1.0.0",
"lcid": "^2.0.0",
"mem": "^4.0.0"
}
},
"p-defer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
"integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww="
},
"p-finally": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
},
"p-is-promise": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz",
"integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg=="
},
"p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"requires": {
"p-try": "^2.0.0"
}
},
"p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"requires": {
"p-limit": "^2.2.0"
}
},
"p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
},
"path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"path-key": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
},
"pathval": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz",
"integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA="
},
"pump": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
"requires": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
}
},
"r1csfile": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/r1csfile/-/r1csfile-0.0.5.tgz",
"integrity": "sha512-B+BdKPb/WUTp4N/3X4d1Spgx9Ojx5tFVejGZRJxpTtzq34mC8Vi/czWfiPj85V8kud31lCfYcZ16z7+czvM0Sw==",
"requires": {
"fastfile": "0.0.1",
"ffjavascript": "0.1.0"
},
"dependencies": {
"ffjavascript": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.1.0.tgz",
"integrity": "sha512-dmKlUasSfvUcxBm8nCSKl2x7EFJsXA7OVP8XLFA03T2+6mAc3IiVLC2ambEVOcMOhyhl0vJfVZjM9f9d38D1rw==",
"requires": {
"big-integer": "^1.6.48"
}
}
}
},
"require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
},
"require-main-filename": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
},
"rimraf": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"requires": {
"glob": "^7.1.3"
}
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
},
"set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
},
"shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
"integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
"requires": {
"shebang-regex": "^1.0.0"
}
},
"shebang-regex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
},
"signal-exit": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
"integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA=="
},
"snarkjs": {
"version": "0.1.31",
"resolved": "https://registry.npmjs.org/snarkjs/-/snarkjs-0.1.31.tgz",
"integrity": "sha512-Xu9Ai89GPLUI6hSyVkc6LRE3sUEje7+eokHeKkb4sZuWW4JqPKWRW7ZtwM7VjsisgVM2gVAg9IYsMD4k+MhuPA==",
"requires": {
"chai": "^4.2.0",
"circom_runtime": "0.0.6",
"escape-string-regexp": "^1.0.5",
"ffjavascript": "0.1.0",
"keccak": "^3.0.0",
"r1csfile": "0.0.5",
"yargs": "^12.0.5"
},
"dependencies": {
"ansi-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
},
"cliui": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
"integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
"requires": {
"string-width": "^2.1.1",
"strip-ansi": "^4.0.0",
"wrap-ansi": "^2.0.0"
}
},
"ffjavascript": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.1.0.tgz",
"integrity": "sha512-dmKlUasSfvUcxBm8nCSKl2x7EFJsXA7OVP8XLFA03T2+6mAc3IiVLC2ambEVOcMOhyhl0vJfVZjM9f9d38D1rw==",
"requires": {
"big-integer": "^1.6.48"
}
},
"find-up": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"requires": {
"locate-path": "^3.0.0"
}
},
"get-caller-file": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
"integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w=="
},
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
},
"locate-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
"requires": {
"p-locate": "^3.0.0",
"path-exists": "^3.0.0"
}
},
"p-locate": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
"requires": {
"p-limit": "^2.0.0"
}
},
"path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
"integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
},
"require-main-filename": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
"integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE="
},
"string-width": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
"requires": {
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^4.0.0"
}
},
"strip-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
"requires": {
"ansi-regex": "^3.0.0"
}
},
"wrap-ansi": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
"requires": {
"string-width": "^1.0.1",
"strip-ansi": "^3.0.1"
},
"dependencies": {
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
},
"is-fullwidth-code-point": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"requires": {
"number-is-nan": "^1.0.0"
}
},
"string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
"strip-ansi": "^3.0.0"
}
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"requires": {
"ansi-regex": "^2.0.0"
}
}
}
},
"yargs": {
"version": "12.0.5",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz",
"integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==",
"requires": {
"cliui": "^4.0.0",
"decamelize": "^1.2.0",
"find-up": "^3.0.0",
"get-caller-file": "^1.0.1",
"os-locale": "^3.0.0",
"require-directory": "^2.1.1",
"require-main-filename": "^1.0.1",
"set-blocking": "^2.0.0",
"string-width": "^2.0.0",
"which-module": "^2.0.0",
"y18n": "^3.2.1 || ^4.0.0",
"yargs-parser": "^11.1.1"
}
},
"yargs-parser": {
"version": "11.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz",
"integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==",
"requires": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
}
}
},
"string-width": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.0"
}
},
"strip-ansi": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
"requires": {
"ansi-regex": "^5.0.0"
}
},
"strip-eof": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"requires": {
"has-flag": "^3.0.0"
}
},
"tmp": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.1.0.tgz",
"integrity": "sha512-J7Z2K08jbGcdA1kkQpJSqLF6T0tdQqpR2pnSUXsIchbPdTI9v3e85cLW0d6WDhwuAleOV71j2xWs8qMPfK7nKw==",
"requires": {
"rimraf": "^2.6.3"
}
},
"tmp-promise": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-2.0.2.tgz",
"integrity": "sha512-zl71nFWjPKW2KXs+73gEk8RmqvtAeXPxhWDkTUoa3MSMkjq3I+9OeknjF178MQoMYsdqL730hfzvNfEkePxq9Q==",
"requires": {
"tmp": "0.1.0"
}
},
"type-detect": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
"integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g=="
},
"wasmbuilder": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/wasmbuilder/-/wasmbuilder-0.0.10.tgz",
"integrity": "sha512-zQSvZ7d74d9OvN+mCN6ucNne4QS5/cBBYTHldX0Oe+u9gStY21orapvuX1ajisA7RVIpuFhYg+ZgdySsPfeh0A==",
"requires": {
"big-integer": "^1.6.48"
}
},
"wasmsnark": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/wasmsnark/-/wasmsnark-0.0.10.tgz",
"integrity": "sha512-ARrJWhxvnBJXMERwBcnEnO5ByLwYhJZr1xwac9dl61SN7+1eOmG7Od3SJL1GzU6zaf86b9wza20y1d5ThCecLw==",
"requires": {
"big-integer": "^1.6.42",
"blakejs": "^1.1.0"
}
},
"which": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"requires": {
"isexe": "^2.0.0"
}
},
"which-module": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
},
"wrap-ansi": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
"requires": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"dependencies": {
"ansi-styles": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
"integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
"requires": {
"@types/color-name": "^1.1.1",
"color-convert": "^2.0.1"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
}
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"y18n": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w=="
},
"yargs": {
"version": "15.3.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz",
"integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==",
"requires": {
"cliui": "^6.0.0",
"decamelize": "^1.2.0",
"find-up": "^4.1.0",
"get-caller-file": "^2.0.1",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^4.2.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^18.1.1"
}
},
"yargs-parser": {
"version": "18.1.3",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
"requires": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
}
}
}

16
testdata/package.json vendored Normal file
View File

@@ -0,0 +1,16 @@
{
"name": "binformat",
"version": "0.0.1",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "GPL-3.0",
"dependencies": {
"wasmsnark": "0.0.10",
"circom": "^0.5.11",
"snarkjs": "^0.1.31"
}
}

View File

@@ -6,6 +6,8 @@ import (
bn256 "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare"
)
var Q, _ = new(big.Int).SetString("21888242871839275222246405745257275088696311157297823662689037894645226208583", 10)
// R is the mod of the finite field
var R, _ = new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10)

View File

@@ -17,6 +17,7 @@ type Vk struct {
IC []*bn256.G1
}
// Verify verifies the Groth16 zkSNARK proof
func Verify(vk *types.Vk, proof *types.Proof, inputs []*big.Int) bool {
if len(inputs)+1 != len(vk.IC) {
fmt.Println("len(inputs)+1 != len(vk.IC)")