18 Commits

Author SHA1 Message Date
arnaucube
478006134d Archive repository 2021-06-13 18:54:21 +02:00
arnaucube
aec3022978 Update README.md 2020-04-14 18:20:19 +02:00
arnau
2461f86bda Merge pull request #14 from KimiWu123/master
follow whitespace rule of strings.TrimSpace
2019-10-31 11:39:20 +01:00
kimiwu123
3308c3d94e follow whitespace rule of strings.TrimSpace 2019-10-31 15:18:01 +08:00
2cbba4e007 add verify proof generated from snarkjs 2019-07-30 22:28:42 +02:00
arnaucube
469eabd451 split trustedsetup in Pk & Vk for proof generation & verification smaller inputs 2019-07-28 12:56:13 +02:00
arnaucube
41f7a3518a remove circuit parameter from proof Verification 2019-07-27 18:11:28 +02:00
arnaucube
e98a97e9fe add wasm for Groth16 proof generation & verification 2019-07-10 21:06:02 +02:00
arnaucube
417cc92a97 add wasm snark proof verification function (Pinocchio) 2019-06-24 21:02:42 +02:00
arnaucube
0a162482ee wasm proof generation from browser working. Added cli wasm exporters, html&js browser example, wasm wrapper from go 2019-06-24 20:54:22 +02:00
arnaucube
662d92b697 add wasm utils: bigint-string parsers 2019-06-24 12:32:40 +02:00
arnaucube
f57599c091 add Groth16 to cli 2019-06-10 15:12:07 +02:00
arnaucube
e3cd35c1c9 add Groth16 proof generation & verification 2019-06-10 13:07:09 +02:00
arnaucube
fa91b9ffad add Groth16 setup calculation 2019-06-10 11:43:59 +02:00
arnaucube
a37361abf7 add gitter button 2019-06-07 22:57:04 +02:00
arnaucube
7b1a15df7f add travis 2019-06-03 18:47:30 +02:00
arnaucube
de5b60b826 add allow import circuits in circuits language compiler 2019-05-30 21:39:00 +02:00
arnaucube
165699b58f circuitcompiler allow to call declared functions in circuits language 2019-05-25 04:11:39 +02:00
51 changed files with 3346 additions and 202 deletions

10
.travis.yml Normal file
View File

@@ -0,0 +1,10 @@
language: go
go:
- "1.12"
env:
- GO111MODULE=on
before_install: rm wasm/go-snark-wasm-wrapper.go

View File

@@ -1,18 +1,21 @@
# go-snark [![Go Report Card](https://goreportcard.com/badge/github.com/arnaucube/go-snark)](https://goreportcard.com/report/github.com/arnaucube/go-snark)
### Warning
Implementation of the zkSNARK [Pinocchio protocol](https://eprint.iacr.org/2013/279.pdf) and [Groth16 protocol](https://eprint.iacr.org/2016/260.pdf) from scratch in Go done in my free time to understand the concepts. Do not use in production.
If you want to generate proofs & verify them from Go, you can try https://github.com/vocdoni/go-snark, which is implemented using the [bn256](https://github.com/ethereum/go-ethereum/tree/master/crypto/bn256/cloudflare) for the Pairing curve operations for the Groth16 zkSNARK, and it is compatible with [circom](https://github.com/iden3/circom).
# go-snark-study [![Go Report Card](https://goreportcard.com/badge/github.com/arnaucube/go-snark-study)](https://goreportcard.com/report/github.com/arnaucube/go-snark-study) [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark-study?status.svg)](https://godoc.org/github.com/arnaucube/go-snark-study)
zkSNARK library implementation in Go
- `Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture`, Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza https://eprint.iacr.org/2013/879.pdf
- `Pinocchio: Nearly practical verifiable computation`, Bryan Parno, Craig Gentry, Jon Howell, Mariana Raykova https://eprint.iacr.org/2013/279.pdf
- `On the Size of Pairing-based Non-interactive Arguments`, Jens Groth https://eprint.iacr.org/2016/260.pdf
## Caution & Warning
Implementation of the zkSNARK [Pinocchio protocol](https://eprint.iacr.org/2013/279.pdf) from scratch in Go to understand the concepts. Do not use in production.
## Features
Currently allows to do the complete path with [Pinocchio protocol](https://eprint.iacr.org/2013/279.pdf) and [Groth16 protocol](https://eprint.iacr.org/2016/260.pdf) :
Not finished, implementing this in my free time to understand it better, so I don't have much time.
Currently allows to do the complete path with [Pinocchio protocol](https://eprint.iacr.org/2013/279.pdf) :
1. compile circuuit
0. write circuit
1. compile circuit
2. generate trusted setup
3. calculate witness
4. generate proofs
@@ -30,21 +33,16 @@ Minimal complete flow implementation:
- [x] generate proofs
- [x] verify proofs with BN128 pairing
Improvements from the minimal implementation:
- [ ] allow `import` in circuits language
- [ ] allow `for` in circuits language
- [ ] code to flat code (improve circuit compiler)
- [ ] move witness values calculation outside the setup phase
- [ ] Groth16
- [ ] multiple optimizations
## WASM usage
Experimentation with go-snark-study compiled to wasm: https://github.com/arnaucube/go-snark-study/tree/master/wasm
## Usage
- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark?status.svg)](https://godoc.org/github.com/arnaucube/go-snark) zkSnark
- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/bn128?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/bn128) bn128 (more details: https://github.com/arnaucube/go-snark/tree/master/bn128)
- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/fields?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/fields) Finite Fields operations
- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/r1csqap?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/r1csqap) R1CS to QAP (more details: https://github.com/arnaucube/go-snark/tree/master/r1csqap)
- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/circuitcompiler?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/circuitcompiler) Circuit Compiler
- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark-study?status.svg)](https://godoc.org/github.com/arnaucube/go-snark-study) zkSnark
- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark-study/groth16?status.svg)](https://godoc.org/github.com/arnaucube/go-snark-study/groth16) zkSnark Groth16
- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark-study/bn128?status.svg)](https://godoc.org/github.com/arnaucube/go-snark-study/bn128) bn128 (more details: https://github.com/arnaucube/go-snark-study/tree/master/bn128)
- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark-study/fields?status.svg)](https://godoc.org/github.com/arnaucube/go-snark-study/fields) Finite Fields operations
- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark-study/r1csqap?status.svg)](https://godoc.org/github.com/arnaucube/go-snark-study/r1csqap) R1CS to QAP (more details: https://github.com/arnaucube/go-snark-study/tree/master/r1csqap)
- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark-study/circuitcompiler?status.svg)](https://godoc.org/github.com/arnaucube/go-snark-study/circuitcompiler) Circuit Compiler
### CLI usage
*The cli still needs some improvements, such as seting input files, etc.*
@@ -54,9 +52,13 @@ In this example we will follow the equation example from [Vitalik](https://mediu
#### Compile circuit
Having a circuit file `test.circuit`:
```
func test(private s0, public s1):
s2 = s0 * s0
s3 = s2 * s0
func exp3(private a):
b = a * a
c = a * b
return c
func main(private s0, public s1):
s3 = exp3(s0)
s4 = s3 + s0
s5 = s4 + 5
equals(s1, s5)
@@ -79,6 +81,10 @@ In the command line, execute:
```
> ./go-snark-cli compile test.circuit
```
If you want to have the wasm input ready also, add the flag `wasm`
```
> ./go-snark-cli compile test.circuit wasm
```
This will output the `compiledcircuit.json` file.
@@ -89,6 +95,10 @@ Having the `compiledcircuit.json`, now we can generate the `TrustedSetup`:
```
This will create the file `trustedsetup.json` with the TrustedSetup data, and also a `toxic.json` file, with the parameters to delete from the `Trusted Setup`.
If you want to have the wasm input ready also, add the flag `wasm`
```
> ./go-snark-cli trustedsetup wasm
```
#### Generate Proofs
Assumming that we have the `compiledcircuit.json`, `trustedsetup.json`, `privateInputs.json` and the `publicInputs.json` we can now generate the `Proofs` with the following command:
@@ -105,6 +115,16 @@ Having the `proofs.json`, `compiledcircuit.json`, `trustedsetup.json` `publicInp
```
This will return a `true` if the proofs are verified, or a `false` if the proofs are not verified.
### Cli using Groth16
All this process can be done using [Groth16 protocol](https://eprint.iacr.org/2016/260.pdf) protocol:
```
> ./go-snark-cli compile test.circuit
> ./go-snark-cli groth16 trustedsetup
> ./go-snark-cli groth16 genproofs
> ./go-snark-cli verify
```
### Library usage
@@ -112,9 +132,13 @@ Example:
```go
// compile circuit and get the R1CS
flatCode := `
func test(private s0, public s1):
s2 = s0 * s0
s3 = s2 * s0
func exp3(private a):
b = a * a
c = a * b
return c
func main(private s0, public s1):
s3 = exp3(s0)
s4 = s3 + s0
s5 = s4 + 5
equals(s1, s5)
@@ -147,8 +171,8 @@ a, b, c := circuit.GenerateR1CS()
/*
now we have the R1CS from the circuit:
a: [[0 0 1 0 0 0 0 0] [0 0 0 1 0 0 0 0] [0 0 1 0 1 0 0 0] [5 0 0 0 0 1 0 0] [0 0 0 0 0 0 1 0] [0 1 0 0 0 0 0 0] [1 0 0 0 0 0 0 0]]
b: [[0 0 1 0 0 0 0 0] [0 0 1 0 0 0 0 0] [1 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0]]
a: [[0 0 1 0 0 0 0 0] [0 0 1 0 0 0 0 0] [0 0 1 0 1 0 0 0] [5 0 0 0 0 1 0 0] [0 0 0 0 0 0 1 0] [0 1 0 0 0 0 0 0] [1 0 0 0 0 0 0 0]]
b: [[0 0 1 0 0 0 0 0] [0 0 0 1 0 0 0 0] [1 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0]]
c: [[0 0 0 1 0 0 0 0] [0 0 0 0 1 0 0 0] [0 0 0 0 0 1 0 0] [0 0 0 0 0 0 1 0] [0 1 0 0 0 0 0 0] [0 0 0 0 0 0 1 0] [0 0 0 0 0 0 0 1]]
*/
@@ -170,7 +194,22 @@ publicSignalsVerif := []*big.Int{b35Verif}
assert.True(t, VerifyProof(*circuit, setup, proof, publicSignalsVerif, true))
```
##### Verify Proof generated from [snarkjs](https://github.com/iden3/snarkjs)
Is possible with `go-snark-study` to verify proofs generated by `snarkjs`
Example:
```go
verified, err := VerifyFromCircom("circom-test/verification_key.json", "circom-test/proof.json", "circom-test/public.json")
assert.Nil(t, err)
assert.True(t, verified)
```
## Versions
History of versions & tags of this project:
- v0.0.1: zkSnark complete flow working with Pinocchio protocol
- v0.0.2: circuit language improved (allow function calls and file imports)
- v0.0.3: Groth16 zkSnark protocol added
## Test
```
@@ -178,7 +217,7 @@ go test ./... -v
```
## vim/nvim circuit syntax highlighter
For more details and installation instructions see https://github.com/arnaucube/go-snark/tree/master/vim-syntax
For more details and installation instructions see https://github.com/arnaucube/go-snark-study/tree/master/vim-syntax
---

View File

@@ -1,5 +1,5 @@
## Bn128
[![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/bn128?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/bn128) bn128
[![GoDoc](https://godoc.org/github.com/arnaucube/go-snark-study/bn128?status.svg)](https://godoc.org/github.com/arnaucube/go-snark-study/bn128) bn128
Implementation of the bn128 pairing in Go.

View File

@@ -4,7 +4,7 @@ import (
"errors"
"math/big"
"github.com/arnaucube/go-snark/fields"
"github.com/arnaucube/go-snark-study/fields"
)
// Bn128 is the data structure of the BN128

View File

@@ -3,7 +3,7 @@ package bn128
import (
"math/big"
"github.com/arnaucube/go-snark/fields"
"github.com/arnaucube/go-snark-study/fields"
)
type G1 struct {

View File

@@ -3,7 +3,7 @@ package bn128
import (
"math/big"
"github.com/arnaucube/go-snark/fields"
"github.com/arnaucube/go-snark-study/fields"
)
type G2 struct {

View File

@@ -0,0 +1,8 @@
import "circuit-test-2.circuit"
func main(private s0, public s1):
s3 = exp3(s0)
s4 = sum(s3, s0)
s5 = s4 + 5
equals(s1, s5)
out = 1 * 1

View File

@@ -0,0 +1,7 @@
func exp3(private a):
b = a * a
c = a * b
return c
func sum(private a, private b):
c = a + b
return c

View File

@@ -5,7 +5,7 @@ import (
"math/big"
"strconv"
"github.com/arnaucube/go-snark/r1csqap"
"github.com/arnaucube/go-snark-study/r1csqap"
)
// Circuit is the data structure of the compiled circuit

View File

@@ -1,7 +1,9 @@
package circuitcompiler
import (
"bufio"
"math/big"
"os"
"strings"
"testing"
@@ -11,7 +13,7 @@ import (
func TestCircuitParser(t *testing.T) {
// y = x^3 + x + 5
flat := `
func test(private s0, public s1):
func main(private s0, public s1):
s2 = s0 * s0
s3 = s2 * s0
s4 = s3 + s0
@@ -86,3 +88,161 @@ func TestCircuitParser(t *testing.T) {
assert.Equal(t, len(circuit.PublicInputs), 1)
assert.Equal(t, len(circuit.PrivateInputs), 1)
}
func TestCircuitWithFuncCallsParser(t *testing.T) {
// y = x^3 + x + 5
code := `
func exp3(private a):
b = a * a
c = a * b
return c
func sum(private a, private b):
c = a + b
return c
func main(private s0, public s1):
s3 = exp3(s0)
s4 = sum(s3, s0)
s5 = s4 + 5
equals(s1, s5)
out = 1 * 1
`
parser := NewParser(strings.NewReader(code))
circuit, err := parser.Parse()
assert.Nil(t, err)
// flat code to R1CS
a, b, c := circuit.GenerateR1CS()
assert.Equal(t, "s0", circuit.PrivateInputs[0])
assert.Equal(t, "s1", circuit.PublicInputs[0])
assert.Equal(t, []string{"one", "s1", "s0", "b0", "s3", "s4", "s5", "out"}, circuit.Signals)
// expected result
b0 := big.NewInt(int64(0))
b1 := big.NewInt(int64(1))
b5 := big.NewInt(int64(5))
aExpected := [][]*big.Int{
[]*big.Int{b0, b0, b1, b0, b0, b0, b0, b0},
[]*big.Int{b0, b0, b1, b0, b0, b0, b0, b0},
[]*big.Int{b0, b0, b1, b0, b1, b0, b0, b0},
[]*big.Int{b5, b0, b0, b0, b0, b1, b0, b0},
[]*big.Int{b0, b0, b0, b0, b0, b0, b1, b0},
[]*big.Int{b0, b1, b0, b0, b0, b0, b0, b0},
[]*big.Int{b1, b0, b0, b0, b0, b0, b0, b0},
}
bExpected := [][]*big.Int{
[]*big.Int{b0, b0, b1, b0, b0, b0, b0, b0},
[]*big.Int{b0, b0, b0, b1, b0, b0, b0, b0},
[]*big.Int{b1, b0, b0, b0, b0, b0, b0, b0},
[]*big.Int{b1, b0, b0, b0, b0, b0, b0, b0},
[]*big.Int{b1, b0, b0, b0, b0, b0, b0, b0},
[]*big.Int{b1, b0, b0, b0, b0, b0, b0, b0},
[]*big.Int{b1, b0, b0, b0, b0, b0, b0, b0},
}
cExpected := [][]*big.Int{
[]*big.Int{b0, b0, b0, b1, b0, b0, b0, b0},
[]*big.Int{b0, b0, b0, b0, b1, b0, b0, b0},
[]*big.Int{b0, b0, b0, b0, b0, b1, b0, b0},
[]*big.Int{b0, b0, b0, b0, b0, b0, b1, b0},
[]*big.Int{b0, b1, b0, b0, b0, b0, b0, b0},
[]*big.Int{b0, b0, b0, b0, b0, b0, b1, b0},
[]*big.Int{b0, b0, b0, b0, b0, b0, b0, b1},
}
assert.Equal(t, aExpected, a)
assert.Equal(t, bExpected, b)
assert.Equal(t, cExpected, c)
b3 := big.NewInt(int64(3))
privateInputs := []*big.Int{b3}
b35 := big.NewInt(int64(35))
publicInputs := []*big.Int{b35}
// Calculate Witness
w, err := circuit.CalculateWitness(privateInputs, publicInputs)
assert.Nil(t, err)
b9 := big.NewInt(int64(9))
b27 := big.NewInt(int64(27))
b30 := big.NewInt(int64(30))
wExpected := []*big.Int{b1, b35, b3, b9, b27, b30, b35, b1}
assert.Equal(t, wExpected, w)
// circuitJson, _ := json.Marshal(circuit)
// fmt.Println("circuit:", string(circuitJson))
assert.Equal(t, circuit.NPublic, 1)
assert.Equal(t, len(circuit.PublicInputs), 1)
assert.Equal(t, len(circuit.PrivateInputs), 1)
}
func TestCircuitFromFileWithImports(t *testing.T) {
circuitFile, err := os.Open("./circuit-test-1.circuit")
assert.Nil(t, err)
parser := NewParser(bufio.NewReader(circuitFile))
circuit, err := parser.Parse()
assert.Nil(t, err)
// flat code to R1CS
a, b, c := circuit.GenerateR1CS()
assert.Equal(t, "s0", circuit.PrivateInputs[0])
assert.Equal(t, "s1", circuit.PublicInputs[0])
assert.Equal(t, []string{"one", "s1", "s0", "b0", "s3", "s4", "s5", "out"}, circuit.Signals)
// expected result
b0 := big.NewInt(int64(0))
b1 := big.NewInt(int64(1))
b5 := big.NewInt(int64(5))
aExpected := [][]*big.Int{
[]*big.Int{b0, b0, b1, b0, b0, b0, b0, b0},
[]*big.Int{b0, b0, b1, b0, b0, b0, b0, b0},
[]*big.Int{b0, b0, b1, b0, b1, b0, b0, b0},
[]*big.Int{b5, b0, b0, b0, b0, b1, b0, b0},
[]*big.Int{b0, b0, b0, b0, b0, b0, b1, b0},
[]*big.Int{b0, b1, b0, b0, b0, b0, b0, b0},
[]*big.Int{b1, b0, b0, b0, b0, b0, b0, b0},
}
bExpected := [][]*big.Int{
[]*big.Int{b0, b0, b1, b0, b0, b0, b0, b0},
[]*big.Int{b0, b0, b0, b1, b0, b0, b0, b0},
[]*big.Int{b1, b0, b0, b0, b0, b0, b0, b0},
[]*big.Int{b1, b0, b0, b0, b0, b0, b0, b0},
[]*big.Int{b1, b0, b0, b0, b0, b0, b0, b0},
[]*big.Int{b1, b0, b0, b0, b0, b0, b0, b0},
[]*big.Int{b1, b0, b0, b0, b0, b0, b0, b0},
}
cExpected := [][]*big.Int{
[]*big.Int{b0, b0, b0, b1, b0, b0, b0, b0},
[]*big.Int{b0, b0, b0, b0, b1, b0, b0, b0},
[]*big.Int{b0, b0, b0, b0, b0, b1, b0, b0},
[]*big.Int{b0, b0, b0, b0, b0, b0, b1, b0},
[]*big.Int{b0, b1, b0, b0, b0, b0, b0, b0},
[]*big.Int{b0, b0, b0, b0, b0, b0, b1, b0},
[]*big.Int{b0, b0, b0, b0, b0, b0, b0, b1},
}
assert.Equal(t, aExpected, a)
assert.Equal(t, bExpected, b)
assert.Equal(t, cExpected, c)
b3 := big.NewInt(int64(3))
privateInputs := []*big.Int{b3}
b35 := big.NewInt(int64(35))
publicInputs := []*big.Int{b35}
// Calculate Witness
w, err := circuit.CalculateWitness(privateInputs, publicInputs)
assert.Nil(t, err)
b9 := big.NewInt(int64(9))
b27 := big.NewInt(int64(27))
b30 := big.NewInt(int64(30))
wExpected := []*big.Int{b1, b35, b3, b9, b27, b30, b35, b1}
assert.Equal(t, wExpected, w)
// circuitJson, _ := json.Marshal(circuit)
// fmt.Println("circuit:", string(circuitJson))
assert.Equal(t, circuit.NPublic, 1)
assert.Equal(t, len(circuit.PublicInputs), 1)
assert.Equal(t, len(circuit.PrivateInputs), 1)
}

View File

@@ -32,7 +32,7 @@ const (
var eof = rune(0)
func isWhitespace(ch rune) bool {
return ch == ' ' || ch == '\t' || ch == '\n'
return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '\v' || ch == '\f'
}
func isLetter(ch rune) bool {

View File

@@ -1,11 +1,13 @@
package circuitcompiler
import (
"bufio"
"errors"
"fmt"
"io"
"os"
"regexp"
"strconv"
"strings"
)
@@ -68,6 +70,12 @@ func (p *Parser) parseLine() (*Constraint, error) {
if err != nil {
return c, err
}
// get func name
fName := strings.Split(line, "(")[0]
fName = strings.Replace(fName, " ", "", -1)
fName = strings.Replace(fName, " ", "", -1)
c.V1 = fName // so, the name of the func will be in c.V1
// read string inside ( )
rgx := regexp.MustCompile(`\((.*?)\)`)
insideParenthesis := rgx.FindStringSubmatch(line)
@@ -105,20 +113,60 @@ func (p *Parser) parseLine() (*Constraint, error) {
c.V2 = params[1]
return c, nil
}
// if c.Literal == "out" {
// // TODO
// return c, nil
// }
if c.Literal == "return" {
_, varToReturn := p.scanIgnoreWhitespace()
c.Out = varToReturn
return c, nil
}
if c.Literal == "import" {
line, err := p.s.r.ReadString('\n')
if err != nil {
return c, err
}
// read string inside " "
path := strings.TrimLeft(strings.TrimRight(line, `"`), `"`)
path = strings.Replace(path, `"`, "", -1)
path = strings.Replace(path, " ", "", -1)
path = strings.Replace(path, "\n", "", -1)
c.Out = path
return c, nil
}
_, lit = p.scanIgnoreWhitespace() // skip =
c.Literal += lit
// v1
_, lit = p.scanIgnoreWhitespace()
// check if lit is a name of a func that we have declared
if _, ok := circuits[lit]; ok {
// if inside, is calling a declared function
c.Literal = "call"
c.Op = lit // c.Op handles the name of the function called
// put the inputs of the call into the c.PrivateInputs
// format: `funcname(a, b)`
line, err := p.s.r.ReadString(')')
if err != nil {
fmt.Println("ERR", err)
return c, err
}
// read string inside ( )
rgx := regexp.MustCompile(`\((.*?)\)`)
insideParenthesis := rgx.FindStringSubmatch(line)
varsString := strings.Replace(insideParenthesis[1], " ", "", -1)
params := strings.Split(varsString, ",")
c.PrivateInputs = params
return c, nil
}
c.V1 = lit
c.Literal += lit
// operator
_, lit = p.scanIgnoreWhitespace()
if lit == "(" {
panic(errors.New("using not declared function"))
}
c.Op = lit
c.Literal += lit
// v2
@@ -150,39 +198,67 @@ func addToArrayIfNotExist(arr []string, elem string) []string {
return arr
}
func subsIfInMap(original string, m map[string]string) string {
if v, ok := m[original]; ok {
return v
}
return original
}
var circuits map[string]*Circuit
// Parse parses the lines and returns the compiled Circuit
func (p *Parser) Parse() (*Circuit, error) {
circuit := &Circuit{}
circuit.Signals = append(circuit.Signals, "one")
// funcsMap is a map holding the functions names and it's content as Circuit
circuits = make(map[string]*Circuit)
mainExist := false
circuits["main"] = &Circuit{}
callsCount := 0
circuits["main"].Signals = append(circuits["main"].Signals, "one")
nInputs := 0
currCircuit := ""
for {
constraint, err := p.parseLine()
if err != nil {
break
}
if constraint.Literal == "func" {
// the name of the func is in constraint.V1
// check if the name of func is main
if constraint.V1 != "main" {
currCircuit = constraint.V1
circuits[currCircuit] = &Circuit{}
circuits[currCircuit].Constraints = append(circuits[currCircuit].Constraints, *constraint)
continue
}
currCircuit = "main"
mainExist = true
// l, _ := json.Marshal(constraint)
// fmt.Println(string(l))
// one constraint for each input
for _, in := range constraint.PublicInputs {
newConstr := &Constraint{
Op: "in",
Out: in,
}
circuit.Constraints = append(circuit.Constraints, *newConstr)
circuits[currCircuit].Constraints = append(circuits[currCircuit].Constraints, *newConstr)
nInputs++
circuit.Signals = addToArrayIfNotExist(circuit.Signals, in)
circuit.NPublic++
circuits[currCircuit].Signals = addToArrayIfNotExist(circuits[currCircuit].Signals, in)
circuits[currCircuit].NPublic++
}
for _, in := range constraint.PrivateInputs {
newConstr := &Constraint{
Op: "in",
Out: in,
}
circuit.Constraints = append(circuit.Constraints, *newConstr)
circuits[currCircuit].Constraints = append(circuits[currCircuit].Constraints, *newConstr)
nInputs++
circuit.Signals = addToArrayIfNotExist(circuit.Signals, in)
circuits[currCircuit].Signals = addToArrayIfNotExist(circuits[currCircuit].Signals, in)
}
circuit.PublicInputs = constraint.PublicInputs
circuit.PrivateInputs = constraint.PrivateInputs
circuits[currCircuit].PublicInputs = constraint.PublicInputs
circuits[currCircuit].PrivateInputs = constraint.PrivateInputs
continue
}
if constraint.Literal == "equals" {
@@ -193,7 +269,7 @@ func (p *Parser) Parse() (*Circuit, error) {
Out: constraint.V1,
Literal: "equals(" + constraint.V1 + ", " + constraint.V2 + "): " + constraint.V1 + "==" + constraint.V2 + " * 1",
}
circuit.Constraints = append(circuit.Constraints, *constr1)
circuits[currCircuit].Constraints = append(circuits[currCircuit].Constraints, *constr1)
constr2 := &Constraint{
Op: "*",
V1: constraint.V1,
@@ -201,42 +277,73 @@ func (p *Parser) Parse() (*Circuit, error) {
Out: constraint.V2,
Literal: "equals(" + constraint.V1 + ", " + constraint.V2 + "): " + constraint.V2 + "==" + constraint.V1 + " * 1",
}
circuit.Constraints = append(circuit.Constraints, *constr2)
circuits[currCircuit].Constraints = append(circuits[currCircuit].Constraints, *constr2)
continue
}
circuit.Constraints = append(circuit.Constraints, *constraint)
if constraint.Literal == "return" {
currCircuit = ""
continue
}
if constraint.Literal == "call" {
callsCountStr := strconv.Itoa(callsCount)
// for each of the constraints of the called circuit
// add it into the current circuit
signalMap := make(map[string]string)
for i, s := range constraint.PrivateInputs {
// signalMap[s] = circuits[constraint.Op].Constraints[0].PrivateInputs[i]
signalMap[circuits[constraint.Op].Constraints[0].PrivateInputs[i]+callsCountStr] = s
}
// add out to map
signalMap[circuits[constraint.Op].Constraints[len(circuits[constraint.Op].Constraints)-1].Out+callsCountStr] = constraint.Out
for i := 1; i < len(circuits[constraint.Op].Constraints); i++ {
c := circuits[constraint.Op].Constraints[i]
// add constraint, puting unique names to vars
nc := &Constraint{
Op: c.Op,
V1: subsIfInMap(c.V1+callsCountStr, signalMap),
V2: subsIfInMap(c.V2+callsCountStr, signalMap),
Out: subsIfInMap(c.Out+callsCountStr, signalMap),
Literal: "",
}
nc.Literal = nc.Out + "=" + nc.V1 + nc.Op + nc.V2
circuits[currCircuit].Constraints = append(circuits[currCircuit].Constraints, *nc)
}
for _, s := range circuits[constraint.Op].Signals {
circuits[currCircuit].Signals = addToArrayIfNotExist(circuits[currCircuit].Signals, subsIfInMap(s+callsCountStr, signalMap))
}
callsCount++
continue
}
if constraint.Literal == "import" {
circuitFile, err := os.Open(constraint.Out)
if err != nil {
panic(errors.New("imported path error: " + constraint.Out))
}
parser := NewParser(bufio.NewReader(circuitFile))
_, err = parser.Parse() // this will add the imported file funcs into the `circuits` map
continue
}
circuits[currCircuit].Constraints = append(circuits[currCircuit].Constraints, *constraint)
isVal, _ := isValue(constraint.V1)
if !isVal {
circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V1)
circuits[currCircuit].Signals = addToArrayIfNotExist(circuits[currCircuit].Signals, constraint.V1)
}
isVal, _ = isValue(constraint.V2)
if !isVal {
circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V2)
circuits[currCircuit].Signals = addToArrayIfNotExist(circuits[currCircuit].Signals, constraint.V2)
}
// if constraint.Out == "out" {
// if Out is "out", put it after first value (one) and before the inputs
// if constraint.Out == circuit.PublicInputs[0] {
// if existInArray(circuit.PublicInputs, constraint.Out) {
// // if Out is a public signal, put it after first value (one) and before the private inputs
// if !existInArray(circuit.Signals, constraint.Out) {
// // if already don't exists in signal array
// signalsCopy := copyArray(circuit.Signals)
// var auxSignals []string
// auxSignals = append(auxSignals, signalsCopy[0])
// auxSignals = append(auxSignals, constraint.Out)
// auxSignals = append(auxSignals, signalsCopy[1:]...)
// circuit.Signals = auxSignals
// // circuit.PublicInputs = append(circuit.PublicInputs, constraint.Out)
// circuit.NPublic++
// }
// } else {
circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.Out)
// }
circuits[currCircuit].Signals = addToArrayIfNotExist(circuits[currCircuit].Signals, constraint.Out)
}
circuit.NVars = len(circuit.Signals)
circuit.NSignals = len(circuit.Signals)
return circuit, nil
circuits["main"].NVars = len(circuits["main"].Signals)
circuits["main"].NSignals = len(circuits["main"].Signals)
if mainExist == false {
return circuits["main"], errors.New("No 'main' func declared")
}
return circuits["main"], nil
}
func copyArray(in []string) []string { // tmp
var out []string

View File

@@ -1,4 +1,4 @@
func test(private a, private b, public c):
func main(private a, private b, public c):
d = a * b
equals(c, d)
out = 1 * 1

View File

@@ -1,4 +1,4 @@
func test(private s0, public s1):
func main(private s0, public s1):
s2 = s0 * s0
s3 = s2 * s0
s4 = s3 + s0

View File

@@ -0,0 +1,8 @@
import "imported-example.circuit"
func main(private s0, public s1):
s3 = exp3(s0)
s4 = sum(s3, s0)
s5 = s4 + 5
equals(s1, s5)
out = 1 * 1

View File

@@ -0,0 +1,7 @@
func exp3(private a):
b = a * a
c = a * b
return c
func sum(private a, private b):
c = a + b
return c

View File

@@ -11,9 +11,11 @@ import (
"math/big"
"os"
snark "github.com/arnaucube/go-snark"
"github.com/arnaucube/go-snark/circuitcompiler"
"github.com/arnaucube/go-snark/r1csqap"
snark "github.com/arnaucube/go-snark-study"
"github.com/arnaucube/go-snark-study/circuitcompiler"
"github.com/arnaucube/go-snark-study/groth16"
"github.com/arnaucube/go-snark-study/r1csqap"
"github.com/arnaucube/go-snark-study/utils"
"github.com/urfave/cli"
)
@@ -48,12 +50,37 @@ var commands = []cli.Command{
Usage: "verify the snark proofs",
Action: VerifyProofs,
},
{
Name: "groth16",
Aliases: []string{},
Usage: "use groth16 protocol",
Subcommands: []cli.Command{
{
Name: "trustedsetup",
Aliases: []string{},
Usage: "generate trusted setup for a circuit",
Action: Groth16TrustedSetup,
},
{
Name: "genproofs",
Aliases: []string{},
Usage: "generate the snark proofs",
Action: Groth16GenerateProofs,
},
{
Name: "verify",
Aliases: []string{},
Usage: "verify the snark proofs",
Action: Groth16VerifyProofs,
},
},
},
}
func main() {
app := cli.NewApp()
app.Name = "go-snarks-cli"
app.Version = "0.0.1-alpha"
app.Version = "0.0.3-alpha"
app.Flags = []cli.Flag{
cli.StringFlag{Name: "config"},
}
@@ -70,6 +97,11 @@ func CompileCircuit(context *cli.Context) error {
circuitPath := context.Args().Get(0)
wasmFlag := false
if context.Args().Get(1) == "wasm" {
wasmFlag = true
}
// read circuit file
circuitFile, err := os.Open(circuitPath)
panicErr(err)
@@ -159,10 +191,48 @@ func CompileCircuit(context *cli.Context) error {
jsonFile.Close()
fmt.Println("Compiled Circuit data written to ", jsonFile.Name())
if wasmFlag {
circuitString := utils.CircuitToString(*circuit)
jsonData, err := json.Marshal(circuitString)
panicErr(err)
// store setup into file
jsonFile, err := os.Create("compiledcircuitString.json")
panicErr(err)
defer jsonFile.Close()
jsonFile.Write(jsonData)
jsonFile.Close()
}
// store px
jsonData, err = json.Marshal(px)
panicErr(err)
// store setup into file
jsonFile, err = os.Create("px.json")
panicErr(err)
defer jsonFile.Close()
jsonFile.Write(jsonData)
jsonFile.Close()
fmt.Println("Px data written to ", jsonFile.Name())
if wasmFlag {
pxString := utils.ArrayBigIntToString(px)
jsonData, err = json.Marshal(pxString)
panicErr(err)
// store setup into file
jsonFile, err = os.Create("pxString.json")
panicErr(err)
defer jsonFile.Close()
jsonFile.Write(jsonData)
jsonFile.Close()
}
return nil
}
func TrustedSetup(context *cli.Context) error {
wasmFlag := false
if context.Args().Get(0) == "wasm" {
wasmFlag = true
}
// open compiledcircuit.json
compiledcircuitFile, err := ioutil.ReadFile("compiledcircuit.json")
panicErr(err)
@@ -204,8 +274,7 @@ func TrustedSetup(context *cli.Context) error {
var tsetup snark.Setup
tsetup.Pk = setup.Pk
tsetup.Vk = setup.Vk
tsetup.G1T = setup.G1T
tsetup.G2T = setup.G2T
tsetup.Pk.G1T = setup.Pk.G1T
// store setup to json
jsonData, err := json.Marshal(tsetup)
@@ -217,6 +286,17 @@ func TrustedSetup(context *cli.Context) error {
jsonFile.Write(jsonData)
jsonFile.Close()
fmt.Println("Trusted Setup data written to ", jsonFile.Name())
if wasmFlag {
tsetupString := utils.SetupToString(tsetup)
jsonData, err := json.Marshal(tsetupString)
panicErr(err)
// store setup into file
jsonFile, err := os.Create("trustedsetupString.json")
panicErr(err)
defer jsonFile.Close()
jsonFile.Write(jsonData)
jsonFile.Close()
}
return nil
}
@@ -263,10 +343,10 @@ func GenerateProofs(context *cli.Context) error {
hx := snark.Utils.PF.DivisorPolynomial(px, trustedsetup.Pk.Z)
fmt.Println(circuit)
fmt.Println(trustedsetup.G1T)
fmt.Println(trustedsetup.Pk.G1T)
fmt.Println(hx)
fmt.Println(w)
proof, err := snark.GenerateProofs(circuit, trustedsetup, w, px)
proof, err := snark.GenerateProofs(circuit, trustedsetup.Pk, w, px)
panicErr(err)
fmt.Println("\n proofs:")
@@ -293,13 +373,6 @@ func VerifyProofs(context *cli.Context) error {
json.Unmarshal([]byte(string(proofsFile)), &proof)
panicErr(err)
// open compiledcircuit.json
compiledcircuitFile, err := ioutil.ReadFile("compiledcircuit.json")
panicErr(err)
var circuit circuitcompiler.Circuit
json.Unmarshal([]byte(string(compiledcircuitFile)), &circuit)
panicErr(err)
// open trustedsetup.json
trustedsetupFile, err := ioutil.ReadFile("trustedsetup.json")
panicErr(err)
@@ -314,7 +387,159 @@ func VerifyProofs(context *cli.Context) error {
err = json.Unmarshal([]byte(string(publicInputsFile)), &publicSignals)
panicErr(err)
verified := snark.VerifyProof(circuit, trustedsetup, proof, publicSignals, true)
verified := snark.VerifyProof(trustedsetup.Vk, proof, publicSignals, true)
if !verified {
fmt.Println("ERROR: proofs not verified")
} else {
fmt.Println("Proofs verified")
}
return nil
}
func Groth16TrustedSetup(context *cli.Context) error {
// open compiledcircuit.json
compiledcircuitFile, err := ioutil.ReadFile("compiledcircuit.json")
panicErr(err)
var circuit circuitcompiler.Circuit
json.Unmarshal([]byte(string(compiledcircuitFile)), &circuit)
panicErr(err)
// read privateInputs file
privateInputsFile, err := ioutil.ReadFile("privateInputs.json")
panicErr(err)
// read publicInputs file
publicInputsFile, err := ioutil.ReadFile("publicInputs.json")
panicErr(err)
// parse inputs from inputsFile
var inputs circuitcompiler.Inputs
err = json.Unmarshal([]byte(string(privateInputsFile)), &inputs.Private)
panicErr(err)
err = json.Unmarshal([]byte(string(publicInputsFile)), &inputs.Public)
panicErr(err)
// calculate wittness
w, err := circuit.CalculateWitness(inputs.Private, inputs.Public)
panicErr(err)
// R1CS to QAP
alphas, betas, gammas, _ := snark.Utils.PF.R1CSToQAP(circuit.R1CS.A, circuit.R1CS.B, circuit.R1CS.C)
fmt.Println("qap")
fmt.Println(alphas)
fmt.Println(betas)
fmt.Println(gammas)
// calculate trusted setup
setup, err := groth16.GenerateTrustedSetup(len(w), circuit, alphas, betas, gammas)
panicErr(err)
fmt.Println("\nt:", setup.Toxic.T)
// remove setup.Toxic
var tsetup groth16.Setup
tsetup.Pk = setup.Pk
tsetup.Vk = setup.Vk
// store setup to json
jsonData, err := json.Marshal(tsetup)
panicErr(err)
// store setup into file
jsonFile, err := os.Create("trustedsetup.json")
panicErr(err)
defer jsonFile.Close()
jsonFile.Write(jsonData)
jsonFile.Close()
fmt.Println("Trusted Setup data written to ", jsonFile.Name())
return nil
}
func Groth16GenerateProofs(context *cli.Context) error {
// open compiledcircuit.json
compiledcircuitFile, err := ioutil.ReadFile("compiledcircuit.json")
panicErr(err)
var circuit circuitcompiler.Circuit
json.Unmarshal([]byte(string(compiledcircuitFile)), &circuit)
panicErr(err)
// open trustedsetup.json
trustedsetupFile, err := ioutil.ReadFile("trustedsetup.json")
panicErr(err)
var trustedsetup groth16.Setup
json.Unmarshal([]byte(string(trustedsetupFile)), &trustedsetup)
panicErr(err)
// read privateInputs file
privateInputsFile, err := ioutil.ReadFile("privateInputs.json")
panicErr(err)
// read publicInputs file
publicInputsFile, err := ioutil.ReadFile("publicInputs.json")
panicErr(err)
// parse inputs from inputsFile
var inputs circuitcompiler.Inputs
err = json.Unmarshal([]byte(string(privateInputsFile)), &inputs.Private)
panicErr(err)
err = json.Unmarshal([]byte(string(publicInputsFile)), &inputs.Public)
panicErr(err)
// calculate wittness
w, err := circuit.CalculateWitness(inputs.Private, inputs.Public)
panicErr(err)
fmt.Println("witness", w)
// flat code to R1CS
a := circuit.R1CS.A
b := circuit.R1CS.B
c := circuit.R1CS.C
// R1CS to QAP
alphas, betas, gammas, _ := groth16.Utils.PF.R1CSToQAP(a, b, c)
_, _, _, px := groth16.Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
hx := groth16.Utils.PF.DivisorPolynomial(px, trustedsetup.Pk.Z)
fmt.Println(circuit)
fmt.Println(trustedsetup.Pk.PowersTauDelta)
fmt.Println(hx)
fmt.Println(w)
proof, err := groth16.GenerateProofs(circuit, trustedsetup.Pk, w, px)
panicErr(err)
fmt.Println("\n proofs:")
fmt.Println(proof)
// store proofs to json
jsonData, err := json.Marshal(proof)
panicErr(err)
// store proof into file
jsonFile, err := os.Create("proofs.json")
panicErr(err)
defer jsonFile.Close()
jsonFile.Write(jsonData)
jsonFile.Close()
fmt.Println("Proofs data written to ", jsonFile.Name())
return nil
}
func Groth16VerifyProofs(context *cli.Context) error {
// open proofs.json
proofsFile, err := ioutil.ReadFile("proofs.json")
panicErr(err)
var proof groth16.Proof
json.Unmarshal([]byte(string(proofsFile)), &proof)
panicErr(err)
// open trustedsetup.json
trustedsetupFile, err := ioutil.ReadFile("trustedsetup.json")
panicErr(err)
var trustedsetup groth16.Setup
json.Unmarshal([]byte(string(trustedsetupFile)), &trustedsetup)
panicErr(err)
// read publicInputs file
publicInputsFile, err := ioutil.ReadFile("publicInputs.json")
panicErr(err)
var publicSignals []*big.Int
err = json.Unmarshal([]byte(string(publicInputsFile)), &publicSignals)
panicErr(err)
verified := groth16.VerifyProof(trustedsetup.Vk, proof, publicSignals, true)
if !verified {
fmt.Println("ERROR: proofs not verified")
} else {

12
externalVerif/README.md Normal file
View File

@@ -0,0 +1,12 @@
# go-snark-study /externalVerif
Utilities to verify zkSNARK proofs generated by other tools.
## Verify Proof generated from [snarkjs](https://github.com/iden3/snarkjs)
Is possible with `go-snark-study` to verify proofs generated by `snarkjs`
Example:
```go
verified, err := VerifyFromCircom("circom-test/verification_key.json", "circom-test/proof.json", "circom-test/public.json")
assert.Nil(t, err)
assert.True(t, verified)
```

View File

@@ -0,0 +1,8 @@
template Multiplier() {
signal private input a;
signal private input b;
signal output c;
c <== a*b;
}
component main = Multiplier();

View File

@@ -0,0 +1,74 @@
{
"mainCode": "{\n}\n",
"signalName2Idx": {
"one": 0,
"main.a": 2,
"main.b": 3,
"main.c": 1
},
"components": [
{
"name": "main",
"params": {},
"template": "Multiplier",
"inputSignals": 2
}
],
"componentName2Idx": {
"main": 0
},
"signals": [
{
"names": [
"one"
],
"triggerComponents": []
},
{
"names": [
"main.c"
],
"triggerComponents": []
},
{
"names": [
"main.a"
],
"triggerComponents": [
0
]
},
{
"names": [
"main.b"
],
"triggerComponents": [
0
]
}
],
"constraints": [
[
{
"2": "21888242871839275222246405745257275088548364400416034343698204186575808495616"
},
{
"3": "1"
},
{
"1": "21888242871839275222246405745257275088548364400416034343698204186575808495616"
}
]
],
"templates": {
"Multiplier": "function(ctx) {\n ctx.setSignal(\"c\", [], bigInt(ctx.getSignal(\"a\", [])).mul(bigInt(ctx.getSignal(\"b\", []))).mod(__P__));\n ctx.assert(ctx.getSignal(\"c\", []), bigInt(ctx.getSignal(\"a\", [])).mul(bigInt(ctx.getSignal(\"b\", []))).mod(__P__));\n}\n"
},
"functions": {},
"nPrvInputs": 2,
"nPubInputs": 0,
"nInputs": 2,
"nOutputs": 1,
"nVars": 4,
"nConstants": 0,
"nSignals": 4
}

View File

@@ -0,0 +1 @@
{"a": 3, "b": 11}

View File

@@ -0,0 +1,27 @@
{
"pi_a": [
"18388960469390566286541775203573681018272060202314500468244373257908579233056",
"7618815753031896296145768956584956596571516464117106968297323458939823682730",
"1"
],
"pi_b": [
[
"17050824088966017765399151386329118398626450147519924253020767437783796544260",
"19912572158122217836152914282050675315049542075120224143747749799495268338155"
],
[
"20465264120227255663865054937863503553147947378051666554617444700075602812731",
"18655251778322805691388473632530173510779859979743695956359151230786651584957"
],
[
"1",
"0"
]
],
"pi_c": [
"1422784641124790360586256228365363101120672643204565045434023905594849706813",
"8557716062509065082036904136615813135951258906799509331823365499907603810450",
"1"
],
"protocol": "groth"
}

View File

@@ -0,0 +1,221 @@
{
"protocol": "groth",
"nVars": 4,
"nPublic": 1,
"domainBits": 2,
"domainSize": 4,
"polsA": [
{
"1": "1"
},
{
"2": "1"
},
{
"0": "21888242871839275222246405745257275088548364400416034343698204186575808495616"
},
{}
],
"polsB": [
{},
{},
{},
{
"0": "1"
}
],
"polsC": [
{},
{
"0": "21888242871839275222246405745257275088548364400416034343698204186575808495616"
},
{},
{}
],
"A": [
[
"16145916318196730299582072104388453231952213805668281741813587224450782397538",
"4434505318477484327659527264104806919103674231447634885054368605283938696207",
"1"
],
[
"10618406967550056457559358662746625591602641004174976323307214433994084907915",
"1843236360452735081347085412539192450068665510574800388201121698908391533923",
"1"
],
[
"1208972877970123411566574123860641832032384890981476033353526096830198333194",
"777503551507025252294438107100944741641946695980350712141258191590862204805",
"1"
],
[
"0",
"1",
"0"
]
],
"B1": [
[
"0",
"1",
"0"
],
[
"0",
"1",
"0"
],
[
"0",
"1",
"0"
],
[
"1208972877970123411566574123860641832032384890981476033353526096830198333194",
"21110739320332249969951967638156330347054364461317472950547779703054364003778",
"1"
]
],
"B2": [
[
[
"0",
"0"
],
[
"1",
"0"
],
[
"0",
"0"
]
],
[
[
"0",
"0"
],
[
"1",
"0"
],
[
"0",
"0"
]
],
[
[
"0",
"0"
],
[
"1",
"0"
],
[
"0",
"0"
]
],
[
[
"9283666785342556550467669770956850930982548182701254051508520248901282197973",
"11369378229277445316894458966429873744779877313900506577160370623273013178252"
],
[
"10625777544326349817513295021482494426101347915428005055375725845993157551870",
"21401790227434807639472120486932615400751346915707967674912972446672152512583"
],
[
"1",
"0"
]
]
],
"C": [
null,
null,
[
"18545397130363256321926549041639729743141431075318462370025152832852939073307",
"2616861286119881509516846668252666108741377487742351180864484963773522850295",
"1"
],
[
"2525636894222523143142808451978966577881491159416335121257094078801746645235",
"16535861715720884910945782094658684127457731006848459401043529763859412916301",
"1"
]
],
"vk_alfa_1": [
"16068200068882411629410035093795608526771554471937479213726134794660780102550",
"20501676791339890155108177259376873296876233680064261776170683533526889207340",
"1"
],
"vk_beta_1": [
"5365573823291502335794132193185274277974617763863996013954364593194136465016",
"11644349101388223784378896360832586557929271772024496470708905460439243894584",
"1"
],
"vk_delta_1": [
"15680151079584844532489259722917096938769907841931133291928746685613811358733",
"16784279394546603697881462850128771845781623009095957214568117820968443242506",
"1"
],
"vk_beta_2": [
[
"13973091636763944887728510851169742544309374663995476311690518173988838518856",
"12903946180439304546475897520537621821375470264150438270817301786763517825250"
],
[
"370374369234123593044872519351942112043402224488849374153134091815693350697",
"17423079115073430837335625309232513526393852743032331213038909731579295753224"
],
[
"1",
"0"
]
],
"vk_delta_2": [
[
"1192908377564945353343974763532707545526009748811618581810344379529229172159",
"10373868200341234689659697947697825014338252335089936445608341428888724327154"
],
[
"6258644116885726740914814071115026921733331135830050167672544002787860516536",
"2784479362505735918824286514153638713518597314121639212447411360814573899319"
],
[
"1",
"0"
]
],
"hExps": [
[
"1137454402546542017796495169973321459788661791339116580816039119135416491226",
"10581992627412174102808274058339351114019966039682644500297077873241797449624",
"1"
],
[
"3253811140290017934039655168718326971539049766532829948316663892796117200680",
"3496418280903365070403555364992889823060908616232765866481366503085657668823",
"1"
],
[
"7426424892372059053157891943364774187577620238460342150964457392480230669997",
"14261604113665464620229095737623968407326243628348811684313201927885047569756",
"1"
],
[
"14706800931196014592083141709960980909656368788497354451613143286705158867076",
"8321358240716309588423491516494287064322707776658072083979021495463106099808",
"1"
],
[
"21560594640856118286219580794351895174554979903538723611152363886530011848778",
"15512645592267656573910252616175869133748229079507420222439452334013754939136",
"1"
]
]
}

View File

@@ -0,0 +1,3 @@
[
"33"
]

View File

@@ -0,0 +1,93 @@
{
"protocol": "groth",
"nPublic": 1,
"IC": [
[
"13238385840837109667936052879696151554096578146827286302729161004449442572510",
"7229895880483697230987627368481585486229758623816305076929725978466335833042",
"1"
],
[
"14970768730171390202518134018231251321095352434740566553215758534237407624223",
"11858341424183782282346697815973277820477089967861765360499368718702428507405",
"1"
]
],
"vk_alfa_1": [
"16068200068882411629410035093795608526771554471937479213726134794660780102550",
"20501676791339890155108177259376873296876233680064261776170683533526889207340",
"1"
],
"vk_beta_2": [
[
"13973091636763944887728510851169742544309374663995476311690518173988838518856",
"12903946180439304546475897520537621821375470264150438270817301786763517825250"
],
[
"370374369234123593044872519351942112043402224488849374153134091815693350697",
"17423079115073430837335625309232513526393852743032331213038909731579295753224"
],
[
"1",
"0"
]
],
"vk_gamma_2": [
[
"20123714298473938437207866646336289719062614610167653880378271328974655580609",
"13002533616763316572747276872341370962409012236118399865958073576789163874362"
],
[
"9275552728819724842865155645402980221399400114914205138826048710506018574007",
"9767402488181356088371101345613657976874749415205606884811092820466492903357"
],
[
"1",
"0"
]
],
"vk_delta_2": [
[
"1192908377564945353343974763532707545526009748811618581810344379529229172159",
"10373868200341234689659697947697825014338252335089936445608341428888724327154"
],
[
"6258644116885726740914814071115026921733331135830050167672544002787860516536",
"2784479362505735918824286514153638713518597314121639212447411360814573899319"
],
[
"1",
"0"
]
],
"vk_alfabeta_12": [
[
[
"5808968930823264229923553886264093087733079723496081749582815497064726636649",
"15704206953123342065158329174314435955575427797267883688615695147218681260603"
],
[
"2019376182570496317125733151845779676488434395598091282285101061771413397585",
"5033120379874305142732026662367866621873812132639805141544817513451132976303"
],
[
"6413062281604814018100947958938305639421600365853645030429871508055751771332",
"16501101898595852943280641675936242756163761586970222679114350546638012990295"
]
],
[
[
"7994355756858823685828118366797930607512610071147093396079158087328554257367",
"12608941378902474737301318807093065779176013217938745808277102463837219428790"
],
[
"7722352178656099663978033703115542396108273285932660670008724291332590018773",
"18402524427751774707431639562944919677540025075739837574780127622149131456184"
],
[
"8237540863924877742345165686185155147152873047203223764861378545202201950314",
"885942718772685438966081900822373900701293300627890502324305030525329921651"
]
]
]
}

View File

@@ -0,0 +1,6 @@
[
"1",
"33",
"3",
"11"
]

View File

@@ -0,0 +1,90 @@
package externalVerif
import (
"encoding/json"
"fmt"
"io/ioutil"
"github.com/arnaucube/go-snark-study/groth16"
"github.com/arnaucube/go-snark-study/utils"
)
type CircomProof struct {
PiA [3]string `json:"pi_a"`
PiB [3][2]string `json:"pi_b"`
PiC [3]string `json:"pi_c"`
}
type CircomVk struct {
IC [][3]string `json:"IC"`
Alpha1 [3]string `json:"vk_alfa_1"`
Beta2 [3][2]string `json:"vk_beta_2"`
Gamma2 [3][2]string `json:"vk_gamma_2"`
Delta2 [3][2]string `json:"vk_delta_2"`
AlphaBeta12 [2][3][2]string `json:"vk_alpfabeta_12"` // not really used, for the moment in go-snarks calculed in verification time
}
func VerifyFromCircom(vkPath, proofPath, publicSignalsPath string) (bool, error) {
// open verification_key.json
vkFile, err := ioutil.ReadFile(vkPath)
if err != nil {
return false, err
}
var circomVk CircomVk
json.Unmarshal([]byte(string(vkFile)), &circomVk)
if err != nil {
return false, err
}
var strVk utils.GrothVkString
strVk.IC = circomVk.IC
strVk.G1.Alpha = circomVk.Alpha1
strVk.G2.Beta = circomVk.Beta2
strVk.G2.Gamma = circomVk.Gamma2
strVk.G2.Delta = circomVk.Delta2
vk, err := utils.GrothVkFromString(strVk)
if err != nil {
return false, err
}
fmt.Println("vk parsed:", vk)
// open proof.json
proofsFile, err := ioutil.ReadFile(proofPath)
if err != nil {
return false, err
}
var circomProof CircomProof
json.Unmarshal([]byte(string(proofsFile)), &circomProof)
if err != nil {
return false, err
}
strProof := utils.GrothProofString{
PiA: circomProof.PiA,
PiB: circomProof.PiB,
PiC: circomProof.PiC,
}
proof, err := utils.GrothProofFromString(strProof)
if err != nil {
return false, err
}
fmt.Println("proof parsed:", proof)
// open public.json
publicFile, err := ioutil.ReadFile(publicSignalsPath)
if err != nil {
return false, err
}
var publicStr []string
json.Unmarshal([]byte(string(publicFile)), &publicStr)
if err != nil {
return false, err
}
publicSignals, err := utils.ArrayStringToBigInt(publicStr)
if err != nil {
return false, err
}
fmt.Println("publicSignals parsed:", publicSignals)
verified := groth16.VerifyProof(vk, proof, publicSignals, true)
return verified, nil
}

View File

@@ -0,0 +1,13 @@
package externalVerif
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestVerifyFromCircom(t *testing.T) {
verified, err := VerifyFromCircom("circom-test/verification_key.json", "circom-test/proof.json", "circom-test/public.json")
assert.Nil(t, err)
assert.True(t, verified)
}

View File

@@ -32,35 +32,30 @@ func (fq Fq) One() *big.Int {
func (fq Fq) Add(a, b *big.Int) *big.Int {
r := new(big.Int).Add(a, b)
return new(big.Int).Mod(r, fq.Q)
// return r
}
// Double performs a doubling on the Fq
func (fq Fq) Double(a *big.Int) *big.Int {
r := new(big.Int).Add(a, a)
return new(big.Int).Mod(r, fq.Q)
// return r
}
// Sub performs a subtraction on the Fq
func (fq Fq) Sub(a, b *big.Int) *big.Int {
r := new(big.Int).Sub(a, b)
return new(big.Int).Mod(r, fq.Q)
// return r
}
// Neg performs a negation on the Fq
func (fq Fq) Neg(a *big.Int) *big.Int {
m := new(big.Int).Neg(a)
return new(big.Int).Mod(m, fq.Q)
// return m
}
// Mul performs a multiplication on the Fq
func (fq Fq) Mul(a, b *big.Int) *big.Int {
m := new(big.Int).Mul(a, b)
return new(big.Int).Mod(m, fq.Q)
// return m
}
func (fq Fq) MulScalar(base, e *big.Int) *big.Int {
@@ -125,8 +120,6 @@ func (fq Fq) Rand() (*big.Int, error) {
maxbits := fq.Q.BitLen()
b := make([]byte, (maxbits/8)-1)
// b := make([]byte, 3)
// b := make([]byte, 3)
_, err := rand.Read(b)
if err != nil {
return nil, err
@@ -134,7 +127,7 @@ func (fq Fq) Rand() (*big.Int, error) {
r := new(big.Int).SetBytes(b)
rq := new(big.Int).Mod(r, fq.Q)
// return r over q, nil
// r over q, nil
return rq, nil
}
@@ -170,3 +163,9 @@ func (fq Fq) Equal(a, b *big.Int) bool {
bAff := fq.Affine(b)
return bytes.Equal(aAff.Bytes(), bAff.Bytes())
}
func BigIsOdd(n *big.Int) bool {
one := big.NewInt(int64(1))
and := new(big.Int).And(n, one)
return bytes.Equal(and.Bytes(), big.NewInt(int64(1)).Bytes())
}

View File

@@ -136,12 +136,6 @@ func (fq12 Fq12) Square(a [2][3][2]*big.Int) [2][3][2]*big.Int {
}
}
func BigIsOdd(n *big.Int) bool {
one := big.NewInt(int64(1))
and := new(big.Int).And(n, one)
return bytes.Equal(and.Bytes(), big.NewInt(int64(1)).Bytes())
}
func (fq12 Fq12) Exp(base [2][3][2]*big.Int, e *big.Int) [2][3][2]*big.Int {
// TODO fix bottleneck

Binary file not shown.

2
go.mod
View File

@@ -1,4 +1,4 @@
module github.com/arnaucube/go-snark
module github.com/arnaucube/go-snark-study
require (
github.com/davecgh/go-spew v1.1.1 // indirect

305
groth16/groth16.go Normal file
View File

@@ -0,0 +1,305 @@
// implementation of https://eprint.iacr.org/2016/260.pdf
package groth16
import (
"fmt"
"math/big"
"github.com/arnaucube/go-snark-study/bn128"
"github.com/arnaucube/go-snark-study/circuitcompiler"
"github.com/arnaucube/go-snark-study/fields"
"github.com/arnaucube/go-snark-study/r1csqap"
)
type Pk struct { // Proving Key
BACDelta [][3]*big.Int // {( βui(x)+αvi(x)+wi(x) ) / δ } from l+1 to m
Z []*big.Int
G1 struct {
Alpha [3]*big.Int
Beta [3]*big.Int
Delta [3]*big.Int
At [][3]*big.Int // {a(τ)} from 0 to m
BACGamma [][3]*big.Int // {( βui(x)+αvi(x)+wi(x) ) / γ } from 0 to m
}
G2 struct {
Beta [3][2]*big.Int
Gamma [3][2]*big.Int
Delta [3][2]*big.Int
BACGamma [][3][2]*big.Int // {( βui(x)+αvi(x)+wi(x) ) / γ } from 0 to m
}
PowersTauDelta [][3]*big.Int // powers of τ encrypted in G1 curve, divided by δ
}
type Vk struct {
IC [][3]*big.Int
G1 struct {
Alpha [3]*big.Int
}
G2 struct {
Beta [3][2]*big.Int
Gamma [3][2]*big.Int
Delta [3][2]*big.Int
}
}
// Setup is the data structure holding the Trusted Setup data. The Setup.Toxic sub struct must be destroyed after the GenerateTrustedSetup function is completed
type Setup struct {
Toxic struct {
T *big.Int // trusted setup secret
Kalpha *big.Int
Kbeta *big.Int
Kgamma *big.Int
Kdelta *big.Int
}
// public
Pk Pk
Vk Vk
}
// Proof contains the parameters to proof the zkSNARK
type Proof struct {
PiA [3]*big.Int
PiB [3][2]*big.Int
PiC [3]*big.Int
}
type utils struct {
Bn bn128.Bn128
FqR fields.Fq
PF r1csqap.PolynomialField
}
// Utils is the data structure holding the BN128, FqR Finite Field over R, PolynomialField, that will be used inside the snarks operations
var Utils = prepareUtils()
func prepareUtils() utils {
bn, err := bn128.NewBn128()
if err != nil {
panic(err)
}
// new Finite Field
fqR := fields.NewFq(bn.R)
// new Polynomial Field
pf := r1csqap.NewPolynomialField(fqR)
return utils{
Bn: bn,
FqR: fqR,
PF: pf,
}
}
// GenerateTrustedSetup generates the Trusted Setup from a compiled Circuit. The Setup.Toxic sub data structure must be destroyed
func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, alphas, betas, gammas [][]*big.Int) (Setup, error) {
var setup Setup
var err error
// generate random t value
setup.Toxic.T, err = Utils.FqR.Rand()
if err != nil {
return Setup{}, err
}
setup.Toxic.Kalpha, err = Utils.FqR.Rand()
if err != nil {
return Setup{}, err
}
setup.Toxic.Kbeta, err = Utils.FqR.Rand()
if err != nil {
return Setup{}, err
}
setup.Toxic.Kgamma, err = Utils.FqR.Rand()
if err != nil {
return Setup{}, err
}
setup.Toxic.Kdelta, err = Utils.FqR.Rand()
if err != nil {
return Setup{}, err
}
// z pol
zpol := []*big.Int{big.NewInt(int64(1))}
for i := 1; i < len(alphas)-1; i++ {
zpol = Utils.PF.Mul(
zpol,
[]*big.Int{
Utils.FqR.Neg(
big.NewInt(int64(i))),
big.NewInt(int64(1)),
})
}
setup.Pk.Z = zpol
zt := Utils.PF.Eval(zpol, setup.Toxic.T)
invDelta := Utils.FqR.Inverse(setup.Toxic.Kdelta)
ztinvDelta := Utils.FqR.Mul(invDelta, zt)
// encrypt t values with curve generators
// powers of tau divided by delta
var ptd [][3]*big.Int
ini := Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, ztinvDelta)
ptd = append(ptd, ini)
tEncr := setup.Toxic.T
for i := 1; i < len(zpol); i++ {
ptd = append(ptd, Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, Utils.FqR.Mul(tEncr, ztinvDelta)))
tEncr = Utils.FqR.Mul(tEncr, setup.Toxic.T)
}
// powers of τ encrypted in G1 curve, divided by δ
// (G1 * τ) / δ
setup.Pk.PowersTauDelta = ptd
setup.Pk.G1.Alpha = Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, setup.Toxic.Kalpha)
setup.Pk.G1.Beta = Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, setup.Toxic.Kbeta)
setup.Pk.G1.Delta = Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, setup.Toxic.Kdelta)
setup.Pk.G2.Beta = Utils.Bn.G2.MulScalar(Utils.Bn.G2.G, setup.Toxic.Kbeta)
setup.Pk.G2.Delta = Utils.Bn.G2.MulScalar(Utils.Bn.G2.G, setup.Toxic.Kdelta)
setup.Vk.G1.Alpha = Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, setup.Toxic.Kalpha)
setup.Vk.G2.Beta = Utils.Bn.G2.MulScalar(Utils.Bn.G2.G, setup.Toxic.Kbeta)
setup.Vk.G2.Gamma = Utils.Bn.G2.MulScalar(Utils.Bn.G2.G, setup.Toxic.Kgamma)
setup.Vk.G2.Delta = Utils.Bn.G2.MulScalar(Utils.Bn.G2.G, setup.Toxic.Kdelta)
for i := 0; i < len(circuit.Signals); i++ {
// Pk.G1.At: {a(τ)} from 0 to m
at := Utils.PF.Eval(alphas[i], setup.Toxic.T)
a := Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, at)
setup.Pk.G1.At = append(setup.Pk.G1.At, a)
bt := Utils.PF.Eval(betas[i], setup.Toxic.T)
g1bt := Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, bt)
g2bt := Utils.Bn.G2.MulScalar(Utils.Bn.G2.G, bt)
// G1.BACGamma: {( βui(x)+αvi(x)+wi(x) ) / γ } from 0 to m in G1
setup.Pk.G1.BACGamma = append(setup.Pk.G1.BACGamma, g1bt)
// G2.BACGamma: {( βui(x)+αvi(x)+wi(x) ) / γ } from 0 to m in G2
setup.Pk.G2.BACGamma = append(setup.Pk.G2.BACGamma, g2bt)
}
zero3 := [3]*big.Int{Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero()}
for i := 0; i < circuit.NPublic+1; i++ {
setup.Pk.BACDelta = append(setup.Pk.BACDelta, zero3)
}
for i := circuit.NPublic + 1; i < circuit.NVars; i++ {
// TODO calculate all at, bt, ct outside, to avoid repeating calculations
at := Utils.PF.Eval(alphas[i], setup.Toxic.T)
bt := Utils.PF.Eval(betas[i], setup.Toxic.T)
ct := Utils.PF.Eval(gammas[i], setup.Toxic.T)
c := Utils.FqR.Mul(
invDelta,
Utils.FqR.Add(
Utils.FqR.Add(
Utils.FqR.Mul(at, setup.Toxic.Kbeta),
Utils.FqR.Mul(bt, setup.Toxic.Kalpha),
),
ct,
),
)
g1c := Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, c)
// Pk.BACDelta: {( βui(x)+αvi(x)+wi(x) ) / δ } from l+1 to m
setup.Pk.BACDelta = append(setup.Pk.BACDelta, g1c)
}
for i := 0; i <= circuit.NPublic; i++ {
at := Utils.PF.Eval(alphas[i], setup.Toxic.T)
bt := Utils.PF.Eval(betas[i], setup.Toxic.T)
ct := Utils.PF.Eval(gammas[i], setup.Toxic.T)
ic := Utils.FqR.Mul(
Utils.FqR.Inverse(setup.Toxic.Kgamma),
Utils.FqR.Add(
Utils.FqR.Add(
Utils.FqR.Mul(at, setup.Toxic.Kbeta),
Utils.FqR.Mul(bt, setup.Toxic.Kalpha),
),
ct,
),
)
g1ic := Utils.Bn.G1.MulScalar(Utils.Bn.G1.G, ic)
// used in verifier
setup.Vk.IC = append(setup.Vk.IC, g1ic)
}
return setup, nil
}
// GenerateProofs generates all the parameters to proof the zkSNARK from the Circuit, Setup and the Witness
func GenerateProofs(circuit circuitcompiler.Circuit, pk Pk, w []*big.Int, px []*big.Int) (Proof, error) {
var proof Proof
proof.PiA = [3]*big.Int{Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero()}
proof.PiB = Utils.Bn.Fq6.Zero()
proof.PiC = [3]*big.Int{Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero()}
r, err := Utils.FqR.Rand()
if err != nil {
return Proof{}, err
}
s, err := Utils.FqR.Rand()
if err != nil {
return Proof{}, err
}
// piBG1 will hold all the same than proof.PiB but in G1 curve
piBG1 := [3]*big.Int{Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero()}
for i := 0; i < circuit.NVars; i++ {
proof.PiA = Utils.Bn.G1.Add(proof.PiA, Utils.Bn.G1.MulScalar(pk.G1.At[i], w[i]))
piBG1 = Utils.Bn.G1.Add(piBG1, Utils.Bn.G1.MulScalar(pk.G1.BACGamma[i], w[i]))
proof.PiB = Utils.Bn.G2.Add(proof.PiB, Utils.Bn.G2.MulScalar(pk.G2.BACGamma[i], w[i]))
}
for i := circuit.NPublic + 1; i < circuit.NVars; i++ {
proof.PiC = Utils.Bn.G1.Add(proof.PiC, Utils.Bn.G1.MulScalar(pk.BACDelta[i], w[i]))
}
// piA = (Σ from 0 to m (pk.A * w[i])) + pk.Alpha1 + r * δ
proof.PiA = Utils.Bn.G1.Add(proof.PiA, pk.G1.Alpha)
deltaR := Utils.Bn.G1.MulScalar(pk.G1.Delta, r)
proof.PiA = Utils.Bn.G1.Add(proof.PiA, deltaR)
// piBG1 = (Σ from 0 to m (pk.B1 * w[i])) + pk.g1.Beta + s * δ
// piB = piB2 = (Σ from 0 to m (pk.B2 * w[i])) + pk.g2.Beta + s * δ
piBG1 = Utils.Bn.G1.Add(piBG1, pk.G1.Beta)
proof.PiB = Utils.Bn.G2.Add(proof.PiB, pk.G2.Beta)
deltaSG1 := Utils.Bn.G1.MulScalar(pk.G1.Delta, s)
piBG1 = Utils.Bn.G1.Add(piBG1, deltaSG1)
deltaSG2 := Utils.Bn.G2.MulScalar(pk.G2.Delta, s)
proof.PiB = Utils.Bn.G2.Add(proof.PiB, deltaSG2)
hx := Utils.PF.DivisorPolynomial(px, pk.Z) // maybe move this calculation to a previous step
// piC = (Σ from l+1 to m (w[i] * (pk.g1.Beta + pk.g1.Alpha + pk.C)) + h(tau)) / δ) + piA*s + r*piB - r*s*δ
for i := 0; i < len(hx); i++ {
proof.PiC = Utils.Bn.G1.Add(proof.PiC, Utils.Bn.G1.MulScalar(pk.PowersTauDelta[i], hx[i]))
}
proof.PiC = Utils.Bn.G1.Add(proof.PiC, Utils.Bn.G1.MulScalar(proof.PiA, s))
proof.PiC = Utils.Bn.G1.Add(proof.PiC, Utils.Bn.G1.MulScalar(piBG1, r))
negRS := Utils.FqR.Neg(Utils.FqR.Mul(r, s))
proof.PiC = Utils.Bn.G1.Add(proof.PiC, Utils.Bn.G1.MulScalar(pk.G1.Delta, negRS))
return proof, nil
}
// VerifyProof verifies over the BN128 the Pairings of the Proof
func VerifyProof(vk Vk, proof Proof, publicSignals []*big.Int, debug bool) bool {
icPubl := vk.IC[0]
for i := 0; i < len(publicSignals); i++ {
icPubl = Utils.Bn.G1.Add(icPubl, Utils.Bn.G1.MulScalar(vk.IC[i+1], publicSignals[i]))
}
if !Utils.Bn.Fq12.Equal(
Utils.Bn.Pairing(proof.PiA, proof.PiB),
Utils.Bn.Fq12.Mul(
Utils.Bn.Pairing(vk.G1.Alpha, vk.G2.Beta),
Utils.Bn.Fq12.Mul(
Utils.Bn.Pairing(icPubl, vk.G2.Gamma),
Utils.Bn.Pairing(proof.PiC, vk.G2.Delta)))) {
if debug {
fmt.Println("❌ groth16 verification not passed")
}
return false
}
if debug {
fmt.Println("✓ groth16 verification passed")
}
return true
}

107
groth16/groth16_test.go Normal file
View File

@@ -0,0 +1,107 @@
package groth16
import (
"bytes"
"fmt"
"math/big"
"strings"
"testing"
"time"
"github.com/arnaucube/go-snark-study/circuitcompiler"
"github.com/arnaucube/go-snark-study/r1csqap"
"github.com/stretchr/testify/assert"
)
func TestGroth16MinimalFlow(t *testing.T) {
fmt.Println("testing Groth16 minimal flow")
// circuit function
// y = x^3 + x + 5
code := `
func main(private s0, public s1):
s2 = s0 * s0
s3 = s2 * s0
s4 = s3 + s0
s5 = s4 + 5
equals(s1, s5)
out = 1 * 1
`
fmt.Print("\ncode of the circuit:")
// parse the code
parser := circuitcompiler.NewParser(strings.NewReader(code))
circuit, err := parser.Parse()
assert.Nil(t, err)
b3 := big.NewInt(int64(3))
privateInputs := []*big.Int{b3}
b35 := big.NewInt(int64(35))
publicSignals := []*big.Int{b35}
// wittness
w, err := circuit.CalculateWitness(privateInputs, publicSignals)
assert.Nil(t, err)
// code to R1CS
fmt.Println("\ngenerating R1CS from code")
a, b, c := circuit.GenerateR1CS()
fmt.Println("\nR1CS:")
fmt.Println("a:", a)
fmt.Println("b:", b)
fmt.Println("c:", c)
// R1CS to QAP
// TODO zxQAP is not used and is an old impl, TODO remove
alphas, betas, gammas, _ := Utils.PF.R1CSToQAP(a, b, c)
fmt.Println("qap")
assert.Equal(t, 8, len(alphas))
assert.Equal(t, 8, len(alphas))
assert.Equal(t, 8, len(alphas))
assert.True(t, !bytes.Equal(alphas[1][1].Bytes(), big.NewInt(int64(0)).Bytes()))
ax, bx, cx, px := Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
assert.Equal(t, 7, len(ax))
assert.Equal(t, 7, len(bx))
assert.Equal(t, 7, len(cx))
assert.Equal(t, 13, len(px))
// ---
// from here is the GROTH16
// ---
// calculate trusted setup
fmt.Println("groth")
setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas)
assert.Nil(t, err)
fmt.Println("\nt:", setup.Toxic.T)
hx := Utils.PF.DivisorPolynomial(px, setup.Pk.Z)
div, rem := Utils.PF.Div(px, setup.Pk.Z)
assert.Equal(t, hx, div)
assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(6))
// hx==px/zx so px==hx*zx
assert.Equal(t, px, Utils.PF.Mul(hx, setup.Pk.Z))
// check length of polynomials H(x) and Z(x)
assert.Equal(t, len(hx), len(px)-len(setup.Pk.Z)+1)
proof, err := GenerateProofs(*circuit, setup.Pk, w, px)
assert.Nil(t, err)
// fmt.Println("\n proofs:")
// fmt.Println(proof)
// fmt.Println("public signals:", proof.PublicSignals)
fmt.Println("\nsignals:", circuit.Signals)
fmt.Println("witness:", w)
b35Verif := big.NewInt(int64(35))
publicSignalsVerif := []*big.Int{b35Verif}
before := time.Now()
assert.True(t, VerifyProof(setup.Vk, proof, publicSignalsVerif, true))
fmt.Println("verify proof time elapsed:", time.Since(before))
// check that with another public input the verification returns false
bOtherWrongPublic := big.NewInt(int64(34))
wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic}
assert.True(t, !VerifyProof(setup.Vk, proof, wrongPublicSignalsVerif, false))
}

View File

@@ -1,5 +1,5 @@
## R1CS to Quadratic Arithmetic Program
[![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/r1csqap?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/r1csqap) R1CS to QAP
[![GoDoc](https://godoc.org/github.com/arnaucube/go-snark-study/r1csqap?status.svg)](https://godoc.org/github.com/arnaucube/go-snark-study/r1csqap) R1CS to QAP
- `Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture`, Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza https://eprint.iacr.org/2013/879.pdf
- Vitalik Buterin blog post about QAP https://medium.com/@VitalikButerin/quadratic-arithmetic-programs-from-zero-to-hero-f6d558cea649
- Ariel Gabizon in Zcash blog https://z.cash/blog/snark-explain5

View File

@@ -4,7 +4,7 @@ import (
"bytes"
"math/big"
"github.com/arnaucube/go-snark/fields"
"github.com/arnaucube/go-snark-study/fields"
)
// Transpose transposes the *big.Int matrix

View File

@@ -5,7 +5,7 @@ import (
"math/big"
"testing"
"github.com/arnaucube/go-snark/fields"
"github.com/arnaucube/go-snark-study/fields"
"github.com/stretchr/testify/assert"
)

117
snark.go
View File

@@ -1,3 +1,5 @@
// implementation of https://eprint.iacr.org/2013/879.pdf
package snark
import (
@@ -5,12 +7,35 @@ import (
"math/big"
"os"
"github.com/arnaucube/go-snark/bn128"
"github.com/arnaucube/go-snark/circuitcompiler"
"github.com/arnaucube/go-snark/fields"
"github.com/arnaucube/go-snark/r1csqap"
"github.com/arnaucube/go-snark-study/bn128"
"github.com/arnaucube/go-snark-study/circuitcompiler"
"github.com/arnaucube/go-snark-study/fields"
"github.com/arnaucube/go-snark-study/r1csqap"
)
type Pk struct { // Proving Key pk:=(pkA, pkB, pkC, pkH)
G1T [][3]*big.Int // t encrypted in G1 curve, G1T == Pk.H
A [][3]*big.Int
B [][3][2]*big.Int
C [][3]*big.Int
Kp [][3]*big.Int
Ap [][3]*big.Int
Bp [][3]*big.Int
Cp [][3]*big.Int
Z []*big.Int
}
type Vk struct {
Vka [3][2]*big.Int
Vkb [3]*big.Int
Vkc [3][2]*big.Int
IC [][3]*big.Int
G1Kbg [3]*big.Int // g1 * Kbeta * Kgamma
G2Kbg [3][2]*big.Int // g2 * Kbeta * Kgamma
G2Kg [3][2]*big.Int // g2 * Kgamma
Vkz [3][2]*big.Int
}
// Setup is the data structure holding the Trusted Setup data. The Setup.Toxic sub struct must be destroyed after the GenerateTrustedSetup function is completed
type Setup struct {
Toxic struct {
@@ -26,28 +51,8 @@ type Setup struct {
}
// public
G1T [][3]*big.Int // t encrypted in G1 curve, G1T == Pk.H
G2T [][3][2]*big.Int // t encrypted in G2 curve
Pk struct { // Proving Key pk:=(pkA, pkB, pkC, pkH)
A [][3]*big.Int
B [][3][2]*big.Int
C [][3]*big.Int
Kp [][3]*big.Int
Ap [][3]*big.Int
Bp [][3]*big.Int
Cp [][3]*big.Int
Z []*big.Int
}
Vk struct {
Vka [3][2]*big.Int
Vkb [3]*big.Int
Vkc [3][2]*big.Int
IC [][3]*big.Int
G1Kbg [3]*big.Int // g1 * Kbeta * Kgamma
G2Kbg [3][2]*big.Int // g2 * Kbeta * Kgamma
G2Kg [3][2]*big.Int // g2 * Kgamma
Vkz [3][2]*big.Int
}
Pk Pk
Vk Vk
}
// Proof contains the parameters to proof the zkSNARK
@@ -240,13 +245,13 @@ func GenerateTrustedSetup(witnessLength int, circuit circuitcompiler.Circuit, al
// tEncr = Utils.Bn.Fq1.Mul(tEncr, setup.Toxic.T)
tEncr = Utils.FqR.Mul(tEncr, setup.Toxic.T)
}
setup.G1T = gt1
setup.Pk.G1T = gt1
return setup, nil
}
// GenerateProofs generates all the parameters to proof the zkSNARK from the Circuit, Setup and the Witness
func GenerateProofs(circuit circuitcompiler.Circuit, setup Setup, w []*big.Int, px []*big.Int) (Proof, error) {
func GenerateProofs(circuit circuitcompiler.Circuit, pk Pk, w []*big.Int, px []*big.Int) (Proof, error) {
var proof Proof
proof.PiA = [3]*big.Int{Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero()}
proof.PiAp = [3]*big.Int{Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero()}
@@ -258,38 +263,40 @@ func GenerateProofs(circuit circuitcompiler.Circuit, setup Setup, w []*big.Int,
proof.PiKp = [3]*big.Int{Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero(), Utils.Bn.G1.F.Zero()}
for i := circuit.NPublic + 1; i < circuit.NVars; i++ {
proof.PiA = Utils.Bn.G1.Add(proof.PiA, Utils.Bn.G1.MulScalar(setup.Pk.A[i], w[i]))
proof.PiAp = Utils.Bn.G1.Add(proof.PiAp, Utils.Bn.G1.MulScalar(setup.Pk.Ap[i], w[i]))
proof.PiA = Utils.Bn.G1.Add(proof.PiA, Utils.Bn.G1.MulScalar(pk.A[i], w[i]))
proof.PiAp = Utils.Bn.G1.Add(proof.PiAp, Utils.Bn.G1.MulScalar(pk.Ap[i], w[i]))
}
for i := 0; i < circuit.NVars; i++ {
proof.PiB = Utils.Bn.G2.Add(proof.PiB, Utils.Bn.G2.MulScalar(setup.Pk.B[i], w[i]))
proof.PiBp = Utils.Bn.G1.Add(proof.PiBp, Utils.Bn.G1.MulScalar(setup.Pk.Bp[i], w[i]))
proof.PiB = Utils.Bn.G2.Add(proof.PiB, Utils.Bn.G2.MulScalar(pk.B[i], w[i]))
proof.PiBp = Utils.Bn.G1.Add(proof.PiBp, Utils.Bn.G1.MulScalar(pk.Bp[i], w[i]))
proof.PiC = Utils.Bn.G1.Add(proof.PiC, Utils.Bn.G1.MulScalar(setup.Pk.C[i], w[i]))
proof.PiCp = Utils.Bn.G1.Add(proof.PiCp, Utils.Bn.G1.MulScalar(setup.Pk.Cp[i], w[i]))
proof.PiC = Utils.Bn.G1.Add(proof.PiC, Utils.Bn.G1.MulScalar(pk.C[i], w[i]))
proof.PiCp = Utils.Bn.G1.Add(proof.PiCp, Utils.Bn.G1.MulScalar(pk.Cp[i], w[i]))
proof.PiKp = Utils.Bn.G1.Add(proof.PiKp, Utils.Bn.G1.MulScalar(setup.Pk.Kp[i], w[i]))
proof.PiKp = Utils.Bn.G1.Add(proof.PiKp, Utils.Bn.G1.MulScalar(pk.Kp[i], w[i]))
}
hx := Utils.PF.DivisorPolynomial(px, setup.Pk.Z) // maybe move this calculation to a previous step
hx := Utils.PF.DivisorPolynomial(px, pk.Z) // maybe move this calculation to a previous step
// piH = pkH,0 + sum ( hi * pk H,i ), where pkH = G1T, hi=hx
// proof.PiH = Utils.Bn.G1.Add(proof.PiH, setup.G1T[0])
// proof.PiH = Utils.Bn.G1.Add(proof.PiH, pk.G1T[0])
for i := 0; i < len(hx); i++ {
proof.PiH = Utils.Bn.G1.Add(proof.PiH, Utils.Bn.G1.MulScalar(setup.G1T[i], hx[i]))
proof.PiH = Utils.Bn.G1.Add(proof.PiH, Utils.Bn.G1.MulScalar(pk.G1T[i], hx[i]))
}
return proof, nil
}
// VerifyProof verifies over the BN128 the Pairings of the Proof
func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publicSignals []*big.Int, debug bool) bool {
func VerifyProof(vk Vk, proof Proof, publicSignals []*big.Int, debug bool) bool {
// e(piA, Va) == e(piA', g2)
pairingPiaVa := Utils.Bn.Pairing(proof.PiA, setup.Vk.Vka)
pairingPiaVa := Utils.Bn.Pairing(proof.PiA, vk.Vka)
pairingPiapG2 := Utils.Bn.Pairing(proof.PiAp, Utils.Bn.G2.G)
if !Utils.Bn.Fq12.Equal(pairingPiaVa, pairingPiapG2) {
fmt.Println("❌ e(piA, Va) == e(piA', g2), valid knowledge commitment for A")
if debug {
fmt.Println("❌ e(piA, Va) == e(piA', g2), valid knowledge commitment for A")
}
return false
}
if debug {
@@ -297,10 +304,12 @@ func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publ
}
// e(Vb, piB) == e(piB', g2)
pairingVbPib := Utils.Bn.Pairing(setup.Vk.Vkb, proof.PiB)
pairingVbPib := Utils.Bn.Pairing(vk.Vkb, proof.PiB)
pairingPibpG2 := Utils.Bn.Pairing(proof.PiBp, Utils.Bn.G2.G)
if !Utils.Bn.Fq12.Equal(pairingVbPib, pairingPibpG2) {
fmt.Println("❌ e(Vb, piB) == e(piB', g2), valid knowledge commitment for B")
if debug {
fmt.Println("❌ e(Vb, piB) == e(piB', g2), valid knowledge commitment for B")
}
return false
}
if debug {
@@ -308,10 +317,12 @@ func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publ
}
// e(piC, Vc) == e(piC', g2)
pairingPicVc := Utils.Bn.Pairing(proof.PiC, setup.Vk.Vkc)
pairingPicVc := Utils.Bn.Pairing(proof.PiC, vk.Vkc)
pairingPicpG2 := Utils.Bn.Pairing(proof.PiCp, Utils.Bn.G2.G)
if !Utils.Bn.Fq12.Equal(pairingPicVc, pairingPicpG2) {
fmt.Println("❌ e(piC, Vc) == e(piC', g2), valid knowledge commitment for C")
if debug {
fmt.Println("❌ e(piC, Vc) == e(piC', g2), valid knowledge commitment for C")
}
return false
}
if debug {
@@ -319,18 +330,20 @@ func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publ
}
// Vkx, to then calculate Vkx+piA
vkxpia := setup.Vk.IC[0]
vkxpia := vk.IC[0]
for i := 0; i < len(publicSignals); i++ {
vkxpia = Utils.Bn.G1.Add(vkxpia, Utils.Bn.G1.MulScalar(setup.Vk.IC[i+1], publicSignals[i]))
vkxpia = Utils.Bn.G1.Add(vkxpia, Utils.Bn.G1.MulScalar(vk.IC[i+1], publicSignals[i]))
}
// e(Vkx+piA, piB) == e(piH, Vkz) * e(piC, g2)
if !Utils.Bn.Fq12.Equal(
Utils.Bn.Pairing(Utils.Bn.G1.Add(vkxpia, proof.PiA), proof.PiB), // TODO Add(vkxpia, proof.PiA) can go outside in order to save computation, as is reused later
Utils.Bn.Fq12.Mul(
Utils.Bn.Pairing(proof.PiH, setup.Vk.Vkz),
Utils.Bn.Pairing(proof.PiH, vk.Vkz),
Utils.Bn.Pairing(proof.PiC, Utils.Bn.G2.G))) {
fmt.Println("❌ e(Vkx+piA, piB) == e(piH, Vkz) * e(piC, g2), QAP disibility checked")
if debug {
fmt.Println("❌ e(Vkx+piA, piB) == e(piH, Vkz) * e(piC, g2), QAP disibility checked")
}
return false
}
if debug {
@@ -340,10 +353,10 @@ func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publ
// e(Vkx+piA+piC, g2KbetaKgamma) * e(g1KbetaKgamma, piB)
// == e(piK, g2Kgamma)
piApiC := Utils.Bn.G1.Add(Utils.Bn.G1.Add(vkxpia, proof.PiA), proof.PiC)
pairingPiACG2Kbg := Utils.Bn.Pairing(piApiC, setup.Vk.G2Kbg)
pairingG1KbgPiB := Utils.Bn.Pairing(setup.Vk.G1Kbg, proof.PiB)
pairingPiACG2Kbg := Utils.Bn.Pairing(piApiC, vk.G2Kbg)
pairingG1KbgPiB := Utils.Bn.Pairing(vk.G1Kbg, proof.PiB)
pairingL := Utils.Bn.Fq12.Mul(pairingPiACG2Kbg, pairingG1KbgPiB)
pairingR := Utils.Bn.Pairing(proof.PiKp, setup.Vk.G2Kg)
pairingR := Utils.Bn.Pairing(proof.PiKp, vk.G2Kg)
if !Utils.Bn.Fq12.Equal(pairingL, pairingR) {
fmt.Println("❌ e(Vkx+piA+piC, g2KbetaKgamma) * e(g1KbetaKgamma, piB) == e(piK, g2Kgamma)")
return false

View File

@@ -8,18 +8,18 @@ import (
"testing"
"time"
"github.com/arnaucube/go-snark/circuitcompiler"
"github.com/arnaucube/go-snark/r1csqap"
"github.com/arnaucube/go-snark-study/circuitcompiler"
"github.com/arnaucube/go-snark-study/groth16"
"github.com/arnaucube/go-snark-study/r1csqap"
"github.com/stretchr/testify/assert"
)
func TestZkFromFlatCircuitCode(t *testing.T) {
// compile circuit and get the R1CS
func TestGroth16MinimalFlow(t *testing.T) {
fmt.Println("testing Groth16 minimal flow")
// circuit function
// y = x^3 + x + 5
flatCode := `
func test(private s0, public s1):
code := `
func main(private s0, public s1):
s2 = s0 * s0
s3 = s2 * s0
s4 = s3 + s0
@@ -27,11 +27,122 @@ func TestZkFromFlatCircuitCode(t *testing.T) {
equals(s1, s5)
out = 1 * 1
`
fmt.Print("\nflat code of the circuit:")
fmt.Println(flatCode)
fmt.Print("\ncode of the circuit:")
// parse the code
parser := circuitcompiler.NewParser(strings.NewReader(flatCode))
parser := circuitcompiler.NewParser(strings.NewReader(code))
circuit, err := parser.Parse()
assert.Nil(t, err)
b3 := big.NewInt(int64(3))
privateInputs := []*big.Int{b3}
b35 := big.NewInt(int64(35))
publicSignals := []*big.Int{b35}
// wittness
w, err := circuit.CalculateWitness(privateInputs, publicSignals)
assert.Nil(t, err)
// code to R1CS
fmt.Println("\ngenerating R1CS from code")
a, b, c := circuit.GenerateR1CS()
fmt.Println("\nR1CS:")
fmt.Println("a:", a)
fmt.Println("b:", b)
fmt.Println("c:", c)
// R1CS to QAP
// TODO zxQAP is not used and is an old impl, TODO remove
alphas, betas, gammas, _ := Utils.PF.R1CSToQAP(a, b, c)
fmt.Println("qap")
assert.Equal(t, 8, len(alphas))
assert.Equal(t, 8, len(alphas))
assert.Equal(t, 8, len(alphas))
assert.True(t, !bytes.Equal(alphas[1][1].Bytes(), big.NewInt(int64(0)).Bytes()))
ax, bx, cx, px := Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
assert.Equal(t, 7, len(ax))
assert.Equal(t, 7, len(bx))
assert.Equal(t, 7, len(cx))
assert.Equal(t, 13, len(px))
// ---
// from here is the GROTH16
// ---
// calculate trusted setup
fmt.Println("groth")
setup, err := groth16.GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas)
assert.Nil(t, err)
fmt.Println("\nt:", setup.Toxic.T)
hx := Utils.PF.DivisorPolynomial(px, setup.Pk.Z)
div, rem := Utils.PF.Div(px, setup.Pk.Z)
assert.Equal(t, hx, div)
assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(6))
// hx==px/zx so px==hx*zx
assert.Equal(t, px, Utils.PF.Mul(hx, setup.Pk.Z))
// check length of polynomials H(x) and Z(x)
assert.Equal(t, len(hx), len(px)-len(setup.Pk.Z)+1)
proof, err := groth16.GenerateProofs(*circuit, setup.Pk, w, px)
assert.Nil(t, err)
// fmt.Println("\n proofs:")
// fmt.Println(proof)
// fmt.Println("public signals:", proof.PublicSignals)
fmt.Println("\nsignals:", circuit.Signals)
fmt.Println("witness:", w)
b35Verif := big.NewInt(int64(35))
publicSignalsVerif := []*big.Int{b35Verif}
before := time.Now()
assert.True(t, groth16.VerifyProof(setup.Vk, proof, publicSignalsVerif, true))
fmt.Println("verify proof time elapsed:", time.Since(before))
// check that with another public input the verification returns false
bOtherWrongPublic := big.NewInt(int64(34))
wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic}
assert.True(t, !groth16.VerifyProof(setup.Vk, proof, wrongPublicSignalsVerif, false))
}
func TestZkFromFlatCircuitCode(t *testing.T) {
// compile circuit and get the R1CS
// circuit function
// y = x^3 + x + 5
code := `
func exp3(private a):
b = a * a
c = a * b
return c
func sum(private a, private b):
c = a + b
return c
func main(private s0, public s1):
s3 = exp3(s0)
s4 = sum(s3, s0)
s5 = s4 + 5
equals(s1, s5)
out = 1 * 1
`
// the same code without the functions calling, all in one func
// code := `
// func test(private s0, public s1):
// s2 = s0 * s0
// s3 = s2 * s0
// s4 = s3 + s0
// s5 = s4 + 5
// equals(s1, s5)
// out = 1 * 1
// `
fmt.Print("\ncode of the circuit:")
fmt.Println(code)
// parse the code
parser := circuitcompiler.NewParser(strings.NewReader(code))
circuit, err := parser.Parse()
assert.Nil(t, err)
// fmt.Println("\ncircuit data:", circuit)
@@ -47,8 +158,8 @@ func TestZkFromFlatCircuitCode(t *testing.T) {
w, err := circuit.CalculateWitness(privateInputs, publicSignals)
assert.Nil(t, err)
// flat code to R1CS
fmt.Println("\ngenerating R1CS from flat code")
// code to R1CS
fmt.Println("\ngenerating R1CS from code")
a, b, c := circuit.GenerateR1CS()
fmt.Println("\nR1CS:")
fmt.Println("a:", a)
@@ -110,7 +221,7 @@ func TestZkFromFlatCircuitCode(t *testing.T) {
assert.Equal(t, len(hx), len(px)-len(setup.Pk.Z)+1)
assert.Equal(t, len(hxQAP), len(px)-len(zxQAP)+1)
proof, err := GenerateProofs(*circuit, setup, w, px)
proof, err := GenerateProofs(*circuit, setup.Pk, w, px)
assert.Nil(t, err)
// fmt.Println("\n proofs:")
@@ -122,26 +233,26 @@ func TestZkFromFlatCircuitCode(t *testing.T) {
b35Verif := big.NewInt(int64(35))
publicSignalsVerif := []*big.Int{b35Verif}
before := time.Now()
assert.True(t, VerifyProof(*circuit, setup, proof, publicSignalsVerif, true))
assert.True(t, VerifyProof(setup.Vk, proof, publicSignalsVerif, true))
fmt.Println("verify proof time elapsed:", time.Since(before))
// check that with another public input the verification returns false
bOtherWrongPublic := big.NewInt(int64(34))
wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic}
assert.True(t, !VerifyProof(*circuit, setup, proof, wrongPublicSignalsVerif, true))
assert.True(t, !VerifyProof(setup.Vk, proof, wrongPublicSignalsVerif, false))
}
func TestZkMultiplication(t *testing.T) {
flatCode := `
func test(private a, private b, public c):
code := `
func main(private a, private b, public c):
d = a * b
equals(c, d)
out = 1 * 1
`
fmt.Println("flat code", flatCode)
fmt.Println("code", code)
// parse the code
parser := circuitcompiler.NewParser(strings.NewReader(flatCode))
parser := circuitcompiler.NewParser(strings.NewReader(code))
circuit, err := parser.Parse()
assert.Nil(t, err)
@@ -155,8 +266,8 @@ func TestZkMultiplication(t *testing.T) {
w, err := circuit.CalculateWitness(privateInputs, publicSignals)
assert.Nil(t, err)
// flat code to R1CS
fmt.Println("\ngenerating R1CS from flat code")
// code to R1CS
fmt.Println("\ngenerating R1CS from code")
a, b, c := circuit.GenerateR1CS()
fmt.Println("\nR1CS:")
fmt.Println("a:", a)
@@ -218,7 +329,7 @@ func TestZkMultiplication(t *testing.T) {
assert.Equal(t, len(hx), len(px)-len(setup.Pk.Z)+1)
assert.Equal(t, len(hxQAP), len(px)-len(zxQAP)+1)
proof, err := GenerateProofs(*circuit, setup, w, px)
proof, err := GenerateProofs(*circuit, setup.Pk, w, px)
assert.Nil(t, err)
// fmt.Println("\n proofs:")
@@ -230,20 +341,20 @@ func TestZkMultiplication(t *testing.T) {
b12Verif := big.NewInt(int64(12))
publicSignalsVerif := []*big.Int{b12Verif}
before := time.Now()
assert.True(t, VerifyProof(*circuit, setup, proof, publicSignalsVerif, true))
assert.True(t, VerifyProof(setup.Vk, proof, publicSignalsVerif, true))
fmt.Println("verify proof time elapsed:", time.Since(before))
// check that with another public input the verification returns false
bOtherWrongPublic := big.NewInt(int64(11))
wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic}
assert.True(t, !VerifyProof(*circuit, setup, proof, wrongPublicSignalsVerif, true))
assert.True(t, !VerifyProof(setup.Vk, proof, wrongPublicSignalsVerif, false))
}
func TestMinimalFlow(t *testing.T) {
// circuit function
// y = x^3 + x + 5
flatCode := `
func test(private s0, public s1):
code := `
func main(private s0, public s1):
s2 = s0 * s0
s3 = s2 * s0
s4 = s3 + s0
@@ -251,11 +362,11 @@ func TestMinimalFlow(t *testing.T) {
equals(s1, s5)
out = 1 * 1
`
fmt.Print("\nflat code of the circuit:")
fmt.Println(flatCode)
fmt.Print("\ncode of the circuit:")
fmt.Println(code)
// parse the code
parser := circuitcompiler.NewParser(strings.NewReader(flatCode))
parser := circuitcompiler.NewParser(strings.NewReader(code))
circuit, err := parser.Parse()
assert.Nil(t, err)
@@ -268,8 +379,8 @@ func TestMinimalFlow(t *testing.T) {
w, err := circuit.CalculateWitness(privateInputs, publicSignals)
assert.Nil(t, err)
// flat code to R1CS
fmt.Println("\ngenerating R1CS from flat code")
// code to R1CS
fmt.Println("\ngenerating R1CS from code")
a, b, c := circuit.GenerateR1CS()
fmt.Println("\nR1CS:")
fmt.Println("a:", a)
@@ -307,7 +418,7 @@ func TestMinimalFlow(t *testing.T) {
// check length of polynomials H(x) and Z(x)
assert.Equal(t, len(hx), len(px)-len(setup.Pk.Z)+1)
proof, err := GenerateProofs(*circuit, setup, w, px)
proof, err := GenerateProofs(*circuit, setup.Pk, w, px)
assert.Nil(t, err)
// fmt.Println("\n proofs:")
@@ -319,11 +430,11 @@ func TestMinimalFlow(t *testing.T) {
b35Verif := big.NewInt(int64(35))
publicSignalsVerif := []*big.Int{b35Verif}
before := time.Now()
assert.True(t, VerifyProof(*circuit, setup, proof, publicSignalsVerif, true))
assert.True(t, VerifyProof(setup.Vk, proof, publicSignalsVerif, true))
fmt.Println("verify proof time elapsed:", time.Since(before))
// check that with another public input the verification returns false
bOtherWrongPublic := big.NewInt(int64(34))
wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic}
assert.True(t, !VerifyProof(*circuit, setup, proof, wrongPublicSignalsVerif, true))
assert.True(t, !VerifyProof(setup.Vk, proof, wrongPublicSignalsVerif, false))
}

585
utils/base10parsers.go Normal file
View File

@@ -0,0 +1,585 @@
package utils
import (
"errors"
"math/big"
snark "github.com/arnaucube/go-snark-study"
"github.com/arnaucube/go-snark-study/circuitcompiler"
"github.com/arnaucube/go-snark-study/groth16"
)
// []*big.Int
func ArrayBigIntToString(b []*big.Int) []string {
var o []string
for i := 0; i < len(b); i++ {
o = append(o, b[i].String())
}
return o
}
func ArrayStringToBigInt(s []string) ([]*big.Int, error) {
var px []*big.Int
for i := 0; i < len(s); i++ {
param, ok := new(big.Int).SetString(s[i], 10)
if !ok {
return nil, errors.New("error parsing px from pxString")
}
px = append(px, param)
}
return px, nil
}
// [3]*big.Int
func String3ToBigInt(s [3]string) ([3]*big.Int, error) {
var o [3]*big.Int
for i := 0; i < len(s); i++ {
param, ok := new(big.Int).SetString(s[i], 10)
if !ok {
return o, errors.New("error parsing [3]*big.Int from [3]string")
}
o[i] = param
}
return o, nil
}
func BigInt3ToString(b [3]*big.Int) [3]string {
var o [3]string
o[0] = b[0].String()
o[1] = b[1].String()
o[2] = b[2].String()
return o
}
// [][3]*big.Int
func Array3StringToBigInt(s [][3]string) ([][3]*big.Int, error) {
var o [][3]*big.Int
for i := 0; i < len(s); i++ {
parsed, err := String3ToBigInt(s[i])
if err != nil {
return o, err
}
o = append(o, parsed)
}
return o, nil
}
func Array3BigIntToString(b [][3]*big.Int) [][3]string {
var o [][3]string
for i := 0; i < len(b); i++ {
o = append(o, BigInt3ToString(b[i]))
}
return o
}
func String2ToBigInt(s [2]string) ([2]*big.Int, error) {
var o [2]*big.Int
for i := 0; i < len(s); i++ {
param, ok := new(big.Int).SetString(s[i], 10)
if !ok {
return o, errors.New("error parsing [2]*big.Int from [2]string")
}
o[i] = param
}
return o, nil
}
// [3][2]*big.Int
func String32ToBigInt(s [3][2]string) ([3][2]*big.Int, error) {
var o [3][2]*big.Int
var err error
o[0], err = String2ToBigInt(s[0])
if err != nil {
return o, err
}
o[1], err = String2ToBigInt(s[1])
if err != nil {
return o, err
}
o[2], err = String2ToBigInt(s[2])
if err != nil {
return o, err
}
return o, nil
}
func BigInt32ToString(b [3][2]*big.Int) [3][2]string {
var o [3][2]string
o[0][0] = b[0][0].String()
o[0][1] = b[0][1].String()
o[1][0] = b[1][0].String()
o[1][1] = b[1][1].String()
o[2][0] = b[2][0].String()
o[2][1] = b[2][1].String()
return o
}
// [][3][2]*big.Int
func Array32StringToBigInt(s [][3][2]string) ([][3][2]*big.Int, error) {
var o [][3][2]*big.Int
for i := 0; i < len(s); i++ {
parsed, err := String32ToBigInt(s[i])
if err != nil {
return o, err
}
o = append(o, parsed)
}
return o, nil
}
func Array32BigIntToString(b [][3][2]*big.Int) [][3][2]string {
var o [][3][2]string
for i := 0; i < len(b); i++ {
o = append(o, BigInt32ToString(b[i]))
}
return o
}
// Setup
type SetupString struct {
// public
Pk struct {
G1T [][3]string
A [][3]string
B [][3][2]string
C [][3]string
Kp [][3]string
Ap [][3]string
Bp [][3]string
Cp [][3]string
Z []string
}
Vk struct {
Vka [3][2]string
Vkb [3]string
Vkc [3][2]string
IC [][3]string
G1Kbg [3]string
G2Kbg [3][2]string
G2Kg [3][2]string
Vkz [3][2]string
}
}
func SetupToString(setup snark.Setup) SetupString {
var s SetupString
s.Pk.G1T = Array3BigIntToString(setup.Pk.G1T)
s.Pk.A = Array3BigIntToString(setup.Pk.A)
s.Pk.B = Array32BigIntToString(setup.Pk.B)
s.Pk.C = Array3BigIntToString(setup.Pk.C)
s.Pk.Kp = Array3BigIntToString(setup.Pk.Kp)
s.Pk.Ap = Array3BigIntToString(setup.Pk.Ap)
s.Pk.Bp = Array3BigIntToString(setup.Pk.Bp)
s.Pk.Cp = Array3BigIntToString(setup.Pk.Cp)
s.Pk.Z = ArrayBigIntToString(setup.Pk.Z)
s.Vk.Vka = BigInt32ToString(setup.Vk.Vka)
s.Vk.Vkb = BigInt3ToString(setup.Vk.Vkb)
s.Vk.Vkc = BigInt32ToString(setup.Vk.Vkc)
s.Vk.IC = Array3BigIntToString(setup.Vk.IC)
s.Vk.G1Kbg = BigInt3ToString(setup.Vk.G1Kbg)
s.Vk.G2Kbg = BigInt32ToString(setup.Vk.G2Kbg)
s.Vk.G2Kg = BigInt32ToString(setup.Vk.G2Kg)
s.Vk.Vkz = BigInt32ToString(setup.Vk.Vkz)
return s
}
func SetupFromString(s SetupString) (snark.Setup, error) {
var o snark.Setup
var err error
o.Pk.G1T, err = Array3StringToBigInt(s.Pk.G1T)
if err != nil {
return o, err
}
o.Pk.A, err = Array3StringToBigInt(s.Pk.A)
if err != nil {
return o, err
}
o.Pk.B, err = Array32StringToBigInt(s.Pk.B)
if err != nil {
return o, err
}
o.Pk.C, err = Array3StringToBigInt(s.Pk.C)
if err != nil {
return o, err
}
o.Pk.Kp, err = Array3StringToBigInt(s.Pk.Kp)
if err != nil {
return o, err
}
o.Pk.Ap, err = Array3StringToBigInt(s.Pk.Ap)
if err != nil {
return o, err
}
o.Pk.Bp, err = Array3StringToBigInt(s.Pk.Bp)
if err != nil {
return o, err
}
o.Pk.Cp, err = Array3StringToBigInt(s.Pk.Cp)
if err != nil {
return o, err
}
o.Pk.Z, err = ArrayStringToBigInt(s.Pk.Z)
if err != nil {
return o, err
}
o.Vk.Vka, err = String32ToBigInt(s.Vk.Vka)
if err != nil {
return o, err
}
o.Vk.Vkb, err = String3ToBigInt(s.Vk.Vkb)
if err != nil {
return o, err
}
o.Vk.Vkc, err = String32ToBigInt(s.Vk.Vkc)
if err != nil {
return o, err
}
o.Vk.IC, err = Array3StringToBigInt(s.Vk.IC)
if err != nil {
return o, err
}
o.Vk.G1Kbg, err = String3ToBigInt(s.Vk.G1Kbg)
if err != nil {
return o, err
}
o.Vk.G2Kbg, err = String32ToBigInt(s.Vk.G2Kbg)
if err != nil {
return o, err
}
o.Vk.G2Kg, err = String32ToBigInt(s.Vk.G2Kg)
if err != nil {
return o, err
}
o.Vk.Vkz, err = String32ToBigInt(s.Vk.Vkz)
if err != nil {
return o, err
}
return o, nil
}
// circuit
type CircuitString struct {
NVars int
NPublic int
NSignals int
PrivateInputs []string
PublicInputs []string
Signals []string
Witness []string
Constraints []circuitcompiler.Constraint
R1CS struct {
A [][]string
B [][]string
C [][]string
}
}
func ArrayArrayBigIntToString(b [][]*big.Int) [][]string {
var o [][]string
for i := 0; i < len(b); i++ {
o = append(o, ArrayBigIntToString(b[i]))
}
return o
}
func ArrayArrayStringToBigInt(s [][]string) ([][]*big.Int, error) {
var o [][]*big.Int
for i := 0; i < len(s); i++ {
parsed, err := ArrayStringToBigInt(s[i])
if err != nil {
return o, err
}
o = append(o, parsed)
}
return o, nil
}
func CircuitToString(c circuitcompiler.Circuit) CircuitString {
var cs CircuitString
cs.NVars = c.NVars
cs.NPublic = c.NPublic
cs.NSignals = c.NSignals
cs.PrivateInputs = c.PrivateInputs
cs.PublicInputs = c.PublicInputs
cs.Signals = c.Signals
cs.Witness = ArrayBigIntToString(c.Witness)
cs.Constraints = c.Constraints
cs.R1CS.A = ArrayArrayBigIntToString(c.R1CS.A)
cs.R1CS.B = ArrayArrayBigIntToString(c.R1CS.B)
cs.R1CS.C = ArrayArrayBigIntToString(c.R1CS.C)
return cs
}
func CircuitFromString(cs CircuitString) (circuitcompiler.Circuit, error) {
var c circuitcompiler.Circuit
var err error
c.NVars = cs.NVars
c.NPublic = cs.NPublic
c.NSignals = cs.NSignals
c.PrivateInputs = cs.PrivateInputs
c.PublicInputs = cs.PublicInputs
c.Signals = cs.Signals
c.Witness, err = ArrayStringToBigInt(cs.Witness)
if err != nil {
return c, err
}
c.Constraints = cs.Constraints
c.R1CS.A, err = ArrayArrayStringToBigInt(cs.R1CS.A)
if err != nil {
return c, err
}
c.R1CS.B, err = ArrayArrayStringToBigInt(cs.R1CS.B)
if err != nil {
return c, err
}
c.R1CS.C, err = ArrayArrayStringToBigInt(cs.R1CS.C)
if err != nil {
return c, err
}
return c, nil
}
// Proof
type ProofString struct {
PiA [3]string
PiAp [3]string
PiB [3][2]string
PiBp [3]string
PiC [3]string
PiCp [3]string
PiH [3]string
PiKp [3]string
}
func ProofToString(p snark.Proof) ProofString {
var s ProofString
s.PiA = BigInt3ToString(p.PiA)
s.PiAp = BigInt3ToString(p.PiAp)
s.PiB = BigInt32ToString(p.PiB)
s.PiBp = BigInt3ToString(p.PiBp)
s.PiC = BigInt3ToString(p.PiC)
s.PiCp = BigInt3ToString(p.PiCp)
s.PiH = BigInt3ToString(p.PiH)
s.PiKp = BigInt3ToString(p.PiKp)
return s
}
func ProofFromString(s ProofString) (snark.Proof, error) {
var p snark.Proof
var err error
p.PiA, err = String3ToBigInt(s.PiA)
if err != nil {
return p, err
}
p.PiAp, err = String3ToBigInt(s.PiAp)
if err != nil {
return p, err
}
p.PiB, err = String32ToBigInt(s.PiB)
if err != nil {
return p, err
}
p.PiBp, err = String3ToBigInt(s.PiBp)
if err != nil {
return p, err
}
p.PiC, err = String3ToBigInt(s.PiC)
if err != nil {
return p, err
}
p.PiCp, err = String3ToBigInt(s.PiCp)
if err != nil {
return p, err
}
p.PiH, err = String3ToBigInt(s.PiH)
if err != nil {
return p, err
}
p.PiKp, err = String3ToBigInt(s.PiKp)
if err != nil {
return p, err
}
return p, nil
}
// groth
type GrothPkString struct { // Proving Key
BACDelta [][3]string
Z []string
G1 struct {
Alpha [3]string
Beta [3]string
Delta [3]string
At [][3]string
BACGamma [][3]string
}
G2 struct {
Beta [3][2]string
Gamma [3][2]string
Delta [3][2]string
BACGamma [][3][2]string
}
PowersTauDelta [][3]string
}
type GrothVkString struct {
IC [][3]string
G1 struct {
Alpha [3]string
}
G2 struct {
Beta [3][2]string
Gamma [3][2]string
Delta [3][2]string
}
}
type GrothSetupString struct {
Pk GrothPkString
Vk GrothVkString
}
func GrothSetupToString(setup groth16.Setup) GrothSetupString {
var s GrothSetupString
s.Pk.BACDelta = Array3BigIntToString(setup.Pk.BACDelta)
s.Pk.Z = ArrayBigIntToString(setup.Pk.Z)
s.Pk.G1.Alpha = BigInt3ToString(setup.Pk.G1.Alpha)
s.Pk.G1.Beta = BigInt3ToString(setup.Pk.G1.Beta)
s.Pk.G1.Delta = BigInt3ToString(setup.Pk.G1.Delta)
s.Pk.G1.At = Array3BigIntToString(setup.Pk.G1.At)
s.Pk.G1.BACGamma = Array3BigIntToString(setup.Pk.G1.BACGamma)
s.Pk.G2.Beta = BigInt32ToString(setup.Pk.G2.Beta)
s.Pk.G2.Gamma = BigInt32ToString(setup.Pk.G2.Gamma)
s.Pk.G2.Delta = BigInt32ToString(setup.Pk.G2.Delta)
s.Pk.G2.BACGamma = Array32BigIntToString(setup.Pk.G2.BACGamma)
s.Pk.PowersTauDelta = Array3BigIntToString(setup.Pk.PowersTauDelta)
s.Vk.IC = Array3BigIntToString(setup.Vk.IC)
s.Vk.G1.Alpha = BigInt3ToString(setup.Vk.G1.Alpha)
s.Vk.G2.Beta = BigInt32ToString(setup.Vk.G2.Beta)
s.Vk.G2.Gamma = BigInt32ToString(setup.Vk.G2.Gamma)
s.Vk.G2.Delta = BigInt32ToString(setup.Vk.G2.Delta)
return s
}
func GrothVkFromString(s GrothVkString) (groth16.Vk, error) {
var vk groth16.Vk
var err error
vk.IC, err = Array3StringToBigInt(s.IC)
if err != nil {
return vk, err
}
vk.G1.Alpha, err = String3ToBigInt(s.G1.Alpha)
if err != nil {
return vk, err
}
vk.G2.Beta, err = String32ToBigInt(s.G2.Beta)
if err != nil {
return vk, err
}
vk.G2.Gamma, err = String32ToBigInt(s.G2.Gamma)
if err != nil {
return vk, err
}
vk.G2.Delta, err = String32ToBigInt(s.G2.Delta)
if err != nil {
return vk, err
}
return vk, nil
}
func GrothSetupFromString(s GrothSetupString) (groth16.Setup, error) {
var o groth16.Setup
var err error
o.Pk.BACDelta, err = Array3StringToBigInt(s.Pk.BACDelta)
if err != nil {
return o, err
}
o.Pk.Z, err = ArrayStringToBigInt(s.Pk.Z)
if err != nil {
return o, err
}
o.Pk.G1.Alpha, err = String3ToBigInt(s.Pk.G1.Alpha)
if err != nil {
return o, err
}
o.Pk.G1.Beta, err = String3ToBigInt(s.Pk.G1.Beta)
if err != nil {
return o, err
}
o.Pk.G1.Delta, err = String3ToBigInt(s.Pk.G1.Delta)
if err != nil {
return o, err
}
o.Pk.G1.At, err = Array3StringToBigInt(s.Pk.G1.At)
if err != nil {
return o, err
}
o.Pk.G1.BACGamma, err = Array3StringToBigInt(s.Pk.G1.BACGamma)
if err != nil {
return o, err
}
o.Pk.G2.Beta, err = String32ToBigInt(s.Pk.G2.Beta)
if err != nil {
return o, err
}
o.Pk.G2.Gamma, err = String32ToBigInt(s.Pk.G2.Gamma)
if err != nil {
return o, err
}
o.Pk.G2.Delta, err = String32ToBigInt(s.Pk.G2.Delta)
if err != nil {
return o, err
}
o.Pk.G2.BACGamma, err = Array32StringToBigInt(s.Pk.G2.BACGamma)
if err != nil {
return o, err
}
o.Pk.PowersTauDelta, err = Array3StringToBigInt(s.Pk.PowersTauDelta)
if err != nil {
return o, err
}
o.Vk.IC, err = Array3StringToBigInt(s.Vk.IC)
if err != nil {
return o, err
}
o.Vk.G1.Alpha, err = String3ToBigInt(s.Vk.G1.Alpha)
if err != nil {
return o, err
}
o.Vk.G2.Beta, err = String32ToBigInt(s.Vk.G2.Beta)
if err != nil {
return o, err
}
o.Vk.G2.Gamma, err = String32ToBigInt(s.Vk.G2.Gamma)
if err != nil {
return o, err
}
o.Vk.G2.Delta, err = String32ToBigInt(s.Vk.G2.Delta)
if err != nil {
return o, err
}
return o, nil
}
type GrothProofString struct {
PiA [3]string
PiB [3][2]string
PiC [3]string
}
func GrothProofToString(p groth16.Proof) GrothProofString {
var s GrothProofString
s.PiA = BigInt3ToString(p.PiA)
s.PiB = BigInt32ToString(p.PiB)
s.PiC = BigInt3ToString(p.PiC)
return s
}
func GrothProofFromString(s GrothProofString) (groth16.Proof, error) {
var p groth16.Proof
var err error
p.PiA, err = String3ToBigInt(s.PiA)
if err != nil {
return p, err
}
p.PiB, err = String32ToBigInt(s.PiB)
if err != nil {
return p, err
}
p.PiC, err = String3ToBigInt(s.PiC)
if err != nil {
return p, err
}
return p, nil
}

562
utils/hexparsers.go Normal file
View File

@@ -0,0 +1,562 @@
package utils
import (
"errors"
"fmt"
"math/big"
snark "github.com/arnaucube/go-snark-study"
"github.com/arnaucube/go-snark-study/circuitcompiler"
"github.com/arnaucube/go-snark-study/groth16"
)
// []*big.Int
func ArrayBigIntToHex(b []*big.Int) []string {
var o []string
for i := 0; i < len(b); i++ {
o = append(o, fmt.Sprintf("%x", b[i]))
}
return o
}
func ArrayHexToBigInt(s []string) ([]*big.Int, error) {
var px []*big.Int
for i := 0; i < len(s); i++ {
param, ok := new(big.Int).SetString(s[i], 16)
if !ok {
return nil, errors.New("error parsing px from pxHex")
}
px = append(px, param)
}
return px, nil
}
// [3]*big.Int
func Hex3ToBigInt(s [3]string) ([3]*big.Int, error) {
var o [3]*big.Int
for i := 0; i < len(s); i++ {
param, ok := new(big.Int).SetString(s[i], 16)
if !ok {
return o, errors.New("error parsing [3]*big.Int from [3]string")
}
o[i] = param
}
return o, nil
}
func BigInt3ToHex(b [3]*big.Int) [3]string {
var o [3]string
o[0] = fmt.Sprintf("%x", b[0])
o[1] = fmt.Sprintf("%x", b[1])
o[2] = fmt.Sprintf("%x", b[2])
return o
}
// [][3]*big.Int
func Array3HexToBigInt(s [][3]string) ([][3]*big.Int, error) {
var o [][3]*big.Int
for i := 0; i < len(s); i++ {
parsed, err := Hex3ToBigInt(s[i])
if err != nil {
return o, err
}
o = append(o, parsed)
}
return o, nil
}
func Array3BigIntToHex(b [][3]*big.Int) [][3]string {
var o [][3]string
for i := 0; i < len(b); i++ {
o = append(o, BigInt3ToHex(b[i]))
}
return o
}
func Hex2ToBigInt(s [2]string) ([2]*big.Int, error) {
var o [2]*big.Int
for i := 0; i < len(s); i++ {
param, ok := new(big.Int).SetString(s[i], 16)
if !ok {
return o, errors.New("error parsing [2]*big.Int from [2]string")
}
o[i] = param
}
return o, nil
}
// [3][2]*big.Int
func Hex32ToBigInt(s [3][2]string) ([3][2]*big.Int, error) {
var o [3][2]*big.Int
var err error
o[0], err = Hex2ToBigInt(s[0])
if err != nil {
return o, err
}
o[1], err = Hex2ToBigInt(s[1])
if err != nil {
return o, err
}
o[2], err = Hex2ToBigInt(s[2])
if err != nil {
return o, err
}
return o, nil
}
func BigInt32ToHex(b [3][2]*big.Int) [3][2]string {
var o [3][2]string
o[0][0] = fmt.Sprintf("%x", b[0][0])
o[0][1] = fmt.Sprintf("%x", b[0][1])
o[1][0] = fmt.Sprintf("%x", b[1][0])
o[1][1] = fmt.Sprintf("%x", b[1][1])
o[2][0] = fmt.Sprintf("%x", b[2][0])
o[2][1] = fmt.Sprintf("%x", b[2][1])
return o
}
// [][3][2]*big.Int
func Array32HexToBigInt(s [][3][2]string) ([][3][2]*big.Int, error) {
var o [][3][2]*big.Int
for i := 0; i < len(s); i++ {
parsed, err := Hex32ToBigInt(s[i])
if err != nil {
return o, err
}
o = append(o, parsed)
}
return o, nil
}
func Array32BigIntToHex(b [][3][2]*big.Int) [][3][2]string {
var o [][3][2]string
for i := 0; i < len(b); i++ {
o = append(o, BigInt32ToHex(b[i]))
}
return o
}
// Setup
type PkHex struct {
G1T [][3]string
A [][3]string
B [][3][2]string
C [][3]string
Kp [][3]string
Ap [][3]string
Bp [][3]string
Cp [][3]string
Z []string
}
type VkHex struct {
Vka [3][2]string
Vkb [3]string
Vkc [3][2]string
IC [][3]string
G1Kbg [3]string
G2Kbg [3][2]string
G2Kg [3][2]string
Vkz [3][2]string
}
type SetupHex struct {
Pk PkHex
Vk VkHex
}
func SetupToHex(setup snark.Setup) SetupHex {
var s SetupHex
s.Pk.G1T = Array3BigIntToHex(setup.Pk.G1T)
s.Pk.A = Array3BigIntToHex(setup.Pk.A)
s.Pk.B = Array32BigIntToHex(setup.Pk.B)
s.Pk.C = Array3BigIntToHex(setup.Pk.C)
s.Pk.Kp = Array3BigIntToHex(setup.Pk.Kp)
s.Pk.Ap = Array3BigIntToHex(setup.Pk.Ap)
s.Pk.Bp = Array3BigIntToHex(setup.Pk.Bp)
s.Pk.Cp = Array3BigIntToHex(setup.Pk.Cp)
s.Pk.Z = ArrayBigIntToHex(setup.Pk.Z)
s.Vk.Vka = BigInt32ToHex(setup.Vk.Vka)
s.Vk.Vkb = BigInt3ToHex(setup.Vk.Vkb)
s.Vk.Vkc = BigInt32ToHex(setup.Vk.Vkc)
s.Vk.IC = Array3BigIntToHex(setup.Vk.IC)
s.Vk.G1Kbg = BigInt3ToHex(setup.Vk.G1Kbg)
s.Vk.G2Kbg = BigInt32ToHex(setup.Vk.G2Kbg)
s.Vk.G2Kg = BigInt32ToHex(setup.Vk.G2Kg)
s.Vk.Vkz = BigInt32ToHex(setup.Vk.Vkz)
return s
}
func SetupFromHex(s SetupHex) (snark.Setup, error) {
var o snark.Setup
var err error
o.Pk.G1T, err = Array3HexToBigInt(s.Pk.G1T)
if err != nil {
return o, err
}
o.Pk.A, err = Array3HexToBigInt(s.Pk.A)
if err != nil {
return o, err
}
o.Pk.B, err = Array32HexToBigInt(s.Pk.B)
if err != nil {
return o, err
}
o.Pk.C, err = Array3HexToBigInt(s.Pk.C)
if err != nil {
return o, err
}
o.Pk.Kp, err = Array3HexToBigInt(s.Pk.Kp)
if err != nil {
return o, err
}
o.Pk.Ap, err = Array3HexToBigInt(s.Pk.Ap)
if err != nil {
return o, err
}
o.Pk.Bp, err = Array3HexToBigInt(s.Pk.Bp)
if err != nil {
return o, err
}
o.Pk.Cp, err = Array3HexToBigInt(s.Pk.Cp)
if err != nil {
return o, err
}
o.Pk.Z, err = ArrayHexToBigInt(s.Pk.Z)
if err != nil {
return o, err
}
o.Vk.Vka, err = Hex32ToBigInt(s.Vk.Vka)
if err != nil {
return o, err
}
o.Vk.Vkb, err = Hex3ToBigInt(s.Vk.Vkb)
if err != nil {
return o, err
}
o.Vk.Vkc, err = Hex32ToBigInt(s.Vk.Vkc)
if err != nil {
return o, err
}
o.Vk.IC, err = Array3HexToBigInt(s.Vk.IC)
if err != nil {
return o, err
}
o.Vk.G1Kbg, err = Hex3ToBigInt(s.Vk.G1Kbg)
if err != nil {
return o, err
}
o.Vk.G2Kbg, err = Hex32ToBigInt(s.Vk.G2Kbg)
if err != nil {
return o, err
}
o.Vk.G2Kg, err = Hex32ToBigInt(s.Vk.G2Kg)
if err != nil {
return o, err
}
o.Vk.Vkz, err = Hex32ToBigInt(s.Vk.Vkz)
if err != nil {
return o, err
}
return o, nil
}
// circuit
type CircuitHex struct {
NVars int
NPublic int
NSignals int
PrivateInputs []string
PublicInputs []string
Signals []string
Witness []string
Constraints []circuitcompiler.Constraint
R1CS struct {
A [][]string
B [][]string
C [][]string
}
}
func ArrayArrayBigIntToHex(b [][]*big.Int) [][]string {
var o [][]string
for i := 0; i < len(b); i++ {
o = append(o, ArrayBigIntToHex(b[i]))
}
return o
}
func ArrayArrayHexToBigInt(s [][]string) ([][]*big.Int, error) {
var o [][]*big.Int
for i := 0; i < len(s); i++ {
parsed, err := ArrayHexToBigInt(s[i])
if err != nil {
return o, err
}
o = append(o, parsed)
}
return o, nil
}
func CircuitToHex(c circuitcompiler.Circuit) CircuitHex {
var cs CircuitHex
cs.NVars = c.NVars
cs.NPublic = c.NPublic
cs.NSignals = c.NSignals
cs.PrivateInputs = c.PrivateInputs
cs.PublicInputs = c.PublicInputs
cs.Signals = c.Signals
cs.Witness = ArrayBigIntToHex(c.Witness)
cs.Constraints = c.Constraints
cs.R1CS.A = ArrayArrayBigIntToHex(c.R1CS.A)
cs.R1CS.B = ArrayArrayBigIntToHex(c.R1CS.B)
cs.R1CS.C = ArrayArrayBigIntToHex(c.R1CS.C)
return cs
}
func CircuitFromHex(cs CircuitHex) (circuitcompiler.Circuit, error) {
var c circuitcompiler.Circuit
var err error
c.NVars = cs.NVars
c.NPublic = cs.NPublic
c.NSignals = cs.NSignals
c.PrivateInputs = cs.PrivateInputs
c.PublicInputs = cs.PublicInputs
c.Signals = cs.Signals
c.Witness, err = ArrayHexToBigInt(cs.Witness)
if err != nil {
return c, err
}
c.Constraints = cs.Constraints
c.R1CS.A, err = ArrayArrayHexToBigInt(cs.R1CS.A)
if err != nil {
return c, err
}
c.R1CS.B, err = ArrayArrayHexToBigInt(cs.R1CS.B)
if err != nil {
return c, err
}
c.R1CS.C, err = ArrayArrayHexToBigInt(cs.R1CS.C)
if err != nil {
return c, err
}
return c, nil
}
// Proof
type ProofHex struct {
PiA [3]string
PiAp [3]string
PiB [3][2]string
PiBp [3]string
PiC [3]string
PiCp [3]string
PiH [3]string
PiKp [3]string
}
func ProofToHex(p snark.Proof) ProofHex {
var s ProofHex
s.PiA = BigInt3ToHex(p.PiA)
s.PiAp = BigInt3ToHex(p.PiAp)
s.PiB = BigInt32ToHex(p.PiB)
s.PiBp = BigInt3ToHex(p.PiBp)
s.PiC = BigInt3ToHex(p.PiC)
s.PiCp = BigInt3ToHex(p.PiCp)
s.PiH = BigInt3ToHex(p.PiH)
s.PiKp = BigInt3ToHex(p.PiKp)
return s
}
func ProofFromHex(s ProofHex) (snark.Proof, error) {
var p snark.Proof
var err error
p.PiA, err = Hex3ToBigInt(s.PiA)
if err != nil {
return p, err
}
p.PiAp, err = Hex3ToBigInt(s.PiAp)
if err != nil {
return p, err
}
p.PiB, err = Hex32ToBigInt(s.PiB)
if err != nil {
return p, err
}
p.PiBp, err = Hex3ToBigInt(s.PiBp)
if err != nil {
return p, err
}
p.PiC, err = Hex3ToBigInt(s.PiC)
if err != nil {
return p, err
}
p.PiCp, err = Hex3ToBigInt(s.PiCp)
if err != nil {
return p, err
}
p.PiH, err = Hex3ToBigInt(s.PiH)
if err != nil {
return p, err
}
p.PiKp, err = Hex3ToBigInt(s.PiKp)
if err != nil {
return p, err
}
return p, nil
}
// groth
type GrothPkHex struct { // Proving Key
BACDelta [][3]string
Z []string
G1 struct {
Alpha [3]string
Beta [3]string
Delta [3]string
At [][3]string
BACGamma [][3]string
}
G2 struct {
Beta [3][2]string
Gamma [3][2]string
Delta [3][2]string
BACGamma [][3][2]string
}
PowersTauDelta [][3]string
}
type GrothVkHex struct {
IC [][3]string
G1 struct {
Alpha [3]string
}
G2 struct {
Beta [3][2]string
Gamma [3][2]string
Delta [3][2]string
}
}
type GrothSetupHex struct {
Pk GrothPkHex
Vk GrothVkHex
}
func GrothSetupToHex(setup groth16.Setup) GrothSetupHex {
var s GrothSetupHex
s.Pk.BACDelta = Array3BigIntToHex(setup.Pk.BACDelta)
s.Pk.Z = ArrayBigIntToHex(setup.Pk.Z)
s.Pk.G1.Alpha = BigInt3ToHex(setup.Pk.G1.Alpha)
s.Pk.G1.Beta = BigInt3ToHex(setup.Pk.G1.Beta)
s.Pk.G1.Delta = BigInt3ToHex(setup.Pk.G1.Delta)
s.Pk.G1.At = Array3BigIntToHex(setup.Pk.G1.At)
s.Pk.G1.BACGamma = Array3BigIntToHex(setup.Pk.G1.BACGamma)
s.Pk.G2.Beta = BigInt32ToHex(setup.Pk.G2.Beta)
s.Pk.G2.Gamma = BigInt32ToHex(setup.Pk.G2.Gamma)
s.Pk.G2.Delta = BigInt32ToHex(setup.Pk.G2.Delta)
s.Pk.G2.BACGamma = Array32BigIntToHex(setup.Pk.G2.BACGamma)
s.Pk.PowersTauDelta = Array3BigIntToHex(setup.Pk.PowersTauDelta)
s.Vk.IC = Array3BigIntToHex(setup.Vk.IC)
s.Vk.G1.Alpha = BigInt3ToHex(setup.Vk.G1.Alpha)
s.Vk.G2.Beta = BigInt32ToHex(setup.Vk.G2.Beta)
s.Vk.G2.Gamma = BigInt32ToHex(setup.Vk.G2.Gamma)
s.Vk.G2.Delta = BigInt32ToHex(setup.Vk.G2.Delta)
return s
}
func GrothSetupFromHex(s GrothSetupHex) (groth16.Setup, error) {
var o groth16.Setup
var err error
o.Pk.BACDelta, err = Array3HexToBigInt(s.Pk.BACDelta)
if err != nil {
return o, err
}
o.Pk.Z, err = ArrayHexToBigInt(s.Pk.Z)
if err != nil {
return o, err
}
o.Pk.G1.Alpha, err = Hex3ToBigInt(s.Pk.G1.Alpha)
if err != nil {
return o, err
}
o.Pk.G1.Beta, err = Hex3ToBigInt(s.Pk.G1.Beta)
if err != nil {
return o, err
}
o.Pk.G1.Delta, err = Hex3ToBigInt(s.Pk.G1.Delta)
if err != nil {
return o, err
}
o.Pk.G1.At, err = Array3HexToBigInt(s.Pk.G1.At)
if err != nil {
return o, err
}
o.Pk.G1.BACGamma, err = Array3HexToBigInt(s.Pk.G1.BACGamma)
if err != nil {
return o, err
}
o.Pk.G2.Beta, err = Hex32ToBigInt(s.Pk.G2.Beta)
if err != nil {
return o, err
}
o.Pk.G2.Gamma, err = Hex32ToBigInt(s.Pk.G2.Gamma)
if err != nil {
return o, err
}
o.Pk.G2.Delta, err = Hex32ToBigInt(s.Pk.G2.Delta)
if err != nil {
return o, err
}
o.Pk.G2.BACGamma, err = Array32HexToBigInt(s.Pk.G2.BACGamma)
if err != nil {
return o, err
}
o.Pk.PowersTauDelta, err = Array3HexToBigInt(s.Pk.PowersTauDelta)
if err != nil {
return o, err
}
o.Vk.IC, err = Array3HexToBigInt(s.Vk.IC)
if err != nil {
return o, err
}
o.Vk.G1.Alpha, err = Hex3ToBigInt(s.Vk.G1.Alpha)
if err != nil {
return o, err
}
o.Vk.G2.Beta, err = Hex32ToBigInt(s.Vk.G2.Beta)
if err != nil {
return o, err
}
o.Vk.G2.Gamma, err = Hex32ToBigInt(s.Vk.G2.Gamma)
if err != nil {
return o, err
}
o.Vk.G2.Delta, err = Hex32ToBigInt(s.Vk.G2.Delta)
if err != nil {
return o, err
}
return o, nil
}
type GrothProofHex struct {
PiA [3]string
PiB [3][2]string
PiC [3]string
}
func GrothProofToHex(p groth16.Proof) GrothProofHex {
var s GrothProofHex
s.PiA = BigInt3ToHex(p.PiA)
s.PiB = BigInt32ToHex(p.PiB)
s.PiC = BigInt3ToHex(p.PiC)
return s
}
func GrothProofFromHex(s GrothProofHex) (groth16.Proof, error) {
var p groth16.Proof
var err error
p.PiA, err = Hex3ToBigInt(s.PiA)
if err != nil {
return p, err
}
p.PiB, err = Hex32ToBigInt(s.PiB)
if err != nil {
return p, err
}
p.PiC, err = Hex3ToBigInt(s.PiC)
if err != nil {
return p, err
}
return p, nil
}

View File

@@ -3,8 +3,8 @@
## Installation in vim/nvim using plug
Using [Plug](https://github.com/junegunn/vim-plug), add this lines into the `.vimrc`/`init.vim`:
```
Plug 'arnaucube/go-snark'
Plug 'arnaucube/go-snark', {'rtp': 'vim-syntax'}
Plug 'arnaucube/go-snark-study'
Plug 'arnaucube/go-snark-study', {'rtp': 'vim-syntax'}
```
![screenshot-vim](https://raw.githubusercontent.com/arnaucube/go-snark/master/vim-syntax/screenshot.png "screenshot-vim")
![screenshot-vim](https://raw.githubusercontent.com/arnaucube/go-snark-study/master/vim-syntax/screenshot.png "screenshot-vim")

View File

@@ -24,12 +24,15 @@ syn keyword goSnarkCircuitPrivatePublic private public
syn keyword goSnarkCircuitOut out
syn keyword goSnarkCircuitEquals equals
syn keyword goSnarkCircuitFunction func
syn keyword goSnarkCircuitStatement return
syn keyword goSnarkCircuitImport import
syn match goSnarkCircuitFuncCall /\<\K\k*\ze\s*(/
syn keyword goSnarkCircuitPrivate private nextgroup=goSnarkCircuitInputName skipwhite
syn keyword goSnarkCircuitPublic public nextgroup=goSnarkCircuitInputName skipwhite
syn match goSnarkCircuitInputName '\i\+' contained
syn match goSnarkCircuitBraces "[{}\[\]]"
syn match goSnarkCircuitParens "[()]"
syn region goSnarkCircuitPath start=+"+ skip=+\\\\\|\\"+ end=+"\|$+
syn sync fromstart
syn sync maxlines=100
@@ -44,12 +47,15 @@ hi def link goSnarkCircuitOpSymbols Operator
hi def link goSnarkCircuitFuncCall Function
hi def link goSnarkCircuitEquals Identifier
hi def link goSnarkCircuitFunction Keyword
hi def link goSnarkCircuitStatement Statement
hi def link goSnarkCircuitImport Keyword
hi def link goSnarkCircuitBraces Function
hi def link goSnarkCircuitPrivate Keyword
hi def link goSnarkCircuitPublic Keyword
hi def link goSnarkCircuitInputName Special
hi def link goSnarkCircuitOut Special
hi def link goSnarkCircuitPrivatePublic Keyword
hi def link goSnarkCircuitPath String
let b:current_syntax = "go-snark-circuit"
if main_syntax == 'go-snark-circuit'

3
wasm/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
node_modules
package-lock.json
wasm_exec.js

22
wasm/README.md Normal file
View File

@@ -0,0 +1,22 @@
# go-snark-study wasm
*Warning: this is an ongoing experimentation*
WASM wrappers for zkSNARK Pinocchio & Groth16 protocols.
## Wasm usage
To compile to wasm, inside the `wasm` directory, execute:
```
GOARCH=wasm GOOS=js go build -o go-snark.wasm go-snark-wasm-wrapper.go
```
Add the file `wasm_exec.js` in the directory:
```
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .
```
To see the usage from javascript, check `index.js` file.
Run the http server that allows to load the `.wasm` file:
```
node server.js
```

View File

@@ -0,0 +1,246 @@
package main
import (
"encoding/json"
"math/big"
"syscall/js"
"github.com/arnaucube/go-snark-study"
"github.com/arnaucube/go-snark-study/circuitcompiler"
"github.com/arnaucube/go-snark-study/groth16"
"github.com/arnaucube/go-snark-study/utils"
)
func main() {
c := make(chan struct{}, 0)
println("WASM Go Initialized")
registerCallbacks()
<-c
}
func registerCallbacks() {
js.Global().Set("generateProofs", js.FuncOf(generateProofs))
js.Global().Set("verifyProofs", js.FuncOf(verifyProofs))
js.Global().Set("grothGenerateProofs", js.FuncOf(grothGenerateProofs))
js.Global().Set("grothVerifyProofs", js.FuncOf(grothVerifyProofs))
}
func generateProofs(this js.Value, i []js.Value) interface{} {
var circuitStr utils.CircuitString
err := json.Unmarshal([]byte(i[0].String()), &circuitStr)
if err != nil {
println(i[0].String())
println("error parsing circuit from stringified json")
}
circuit, err := utils.CircuitFromString(circuitStr)
if err != nil {
println("error " + err.Error())
}
sj, err := json.Marshal(circuit)
if err != nil {
println("error " + err.Error())
}
println("circuit", string(sj))
var setupStr utils.SetupString
println(i[1].String())
err = json.Unmarshal([]byte(i[1].String()), &setupStr)
if err != nil {
println("error parsing setup from stringified json")
}
setup, err := utils.SetupFromString(setupStr)
if err != nil {
println("error " + err.Error())
}
sj, err = json.Marshal(setup)
if err != nil {
println("error " + err.Error())
}
println("set", string(sj))
var pxStr []string
err = json.Unmarshal([]byte(i[2].String()), &pxStr)
if err != nil {
println("error parsing pxStr from stringified json")
}
px, err := utils.ArrayStringToBigInt(pxStr)
if err != nil {
println(err.Error())
}
sj, err = json.Marshal(px)
if err != nil {
println("error " + err.Error())
}
println("px", string(sj))
var inputs circuitcompiler.Inputs
err = json.Unmarshal([]byte(i[3].String()), &inputs)
if err != nil {
println("error parsing inputs from stringified json")
}
w, err := circuit.CalculateWitness(inputs.Private, inputs.Public)
proof, err := snark.GenerateProofs(circuit, setup.Pk, w, px)
if err != nil {
println("error generating proof", err)
}
proofString := utils.ProofToString(proof)
proofJson, err := json.Marshal(proofString)
if err != nil {
println("error marshal proof to json", err)
}
println("proofJson", string(proofJson))
return js.ValueOf(string(proofJson))
}
func verifyProofs(this js.Value, i []js.Value) interface{} {
var setupStr utils.SetupString
println(i[0].String())
err := json.Unmarshal([]byte(i[0].String()), &setupStr)
if err != nil {
println("error parsing setup from stringified json")
}
setup, err := utils.SetupFromString(setupStr)
if err != nil {
println("error " + err.Error())
}
var proofStr utils.ProofString
err = json.Unmarshal([]byte(i[1].String()), &proofStr)
if err != nil {
println(i[1].String())
println("error parsing proof from stringified json")
}
proof, err := utils.ProofFromString(proofStr)
if err != nil {
println("error " + err.Error())
}
var publicInputs []*big.Int
err = json.Unmarshal([]byte(i[2].String()), &publicInputs)
if err != nil {
println(i[2].String())
println("error parsing publicInputs from stringified json")
}
verified := snark.VerifyProof(setup.Vk, proof, publicInputs, false)
if err != nil {
println("error verifiyng proof", err)
}
verifiedJson, err := json.Marshal(verified)
if err != nil {
println("error marshal verified to json", err)
}
println("verifiedJson", string(verifiedJson))
return js.ValueOf(string(verifiedJson))
}
func grothGenerateProofs(this js.Value, i []js.Value) interface{} {
var circuitStr utils.CircuitString
err := json.Unmarshal([]byte(i[0].String()), &circuitStr)
if err != nil {
println(i[0].String())
println("error parsing circuit from stringified json")
}
circuit, err := utils.CircuitFromString(circuitStr)
if err != nil {
println("error " + err.Error())
}
sj, err := json.Marshal(circuit)
if err != nil {
println("error " + err.Error())
}
println("circuit", string(sj))
var setupStr utils.GrothSetupString
println(i[1].String())
err = json.Unmarshal([]byte(i[1].String()), &setupStr)
if err != nil {
println("error parsing setup from stringified json")
}
setup, err := utils.GrothSetupFromString(setupStr)
if err != nil {
println("error " + err.Error())
}
sj, err = json.Marshal(setup)
if err != nil {
println("error " + err.Error())
}
println("set", string(sj))
var pxStr []string
err = json.Unmarshal([]byte(i[2].String()), &pxStr)
if err != nil {
println("error parsing pxStr from stringified json")
}
px, err := utils.ArrayStringToBigInt(pxStr)
if err != nil {
println(err.Error())
}
sj, err = json.Marshal(px)
if err != nil {
println("error " + err.Error())
}
println("px", string(sj))
var inputs circuitcompiler.Inputs
err = json.Unmarshal([]byte(i[3].String()), &inputs)
if err != nil {
println("error parsing inputs from stringified json")
}
w, err := circuit.CalculateWitness(inputs.Private, inputs.Public)
proof, err := groth16.GenerateProofs(circuit, setup.Pk, w, px)
if err != nil {
println("error generating proof", err)
}
proofString := utils.GrothProofToString(proof)
proofJson, err := json.Marshal(proofString)
if err != nil {
println("error marshal proof to json", err)
}
println("proofJson", string(proofJson))
return js.ValueOf(string(proofJson))
}
func grothVerifyProofs(this js.Value, i []js.Value) interface{} {
var setupStr utils.GrothSetupString
println(i[0].String())
err := json.Unmarshal([]byte(i[0].String()), &setupStr)
if err != nil {
println("error parsing setup from stringified json")
}
setup, err := utils.GrothSetupFromString(setupStr)
if err != nil {
println("error " + err.Error())
}
var proofStr utils.GrothProofString
err = json.Unmarshal([]byte(i[1].String()), &proofStr)
if err != nil {
println(i[1].String())
println("error parsing proof from stringified json")
}
proof, err := utils.GrothProofFromString(proofStr)
if err != nil {
println("error " + err.Error())
}
var publicInputs []*big.Int
err = json.Unmarshal([]byte(i[2].String()), &publicInputs)
if err != nil {
println(i[2].String())
println("error parsing publicInputs from stringified json")
}
verified := groth16.VerifyProof(setup.Vk, proof, publicInputs, false)
if err != nil {
println("error verifiyng proof", err)
}
verifiedJson, err := json.Marshal(verified)
if err != nil {
println("error marshal verified to json", err)
}
println("verifiedJson", string(verifiedJson))
return js.ValueOf(string(verifiedJson))
}

BIN
wasm/go-snark.wasm Executable file

Binary file not shown.

20
wasm/index.html Normal file
View File

@@ -0,0 +1,20 @@
<html>
<head>
<meta charset="utf-8">
<title>go-snark wasm experiments</title>
</head>
<body>
<script src="wasm_exec.js"></script>
<script>
const go = new Go();
WebAssembly.instantiateStreaming(fetch('go-snark.wasm'), go.importObject).then(function(dat) {
go.run(dat.instance);
});
</script>
<button onClick="callGenerateProof();">Generate Proof</button>
<textarea id="proofResult" rows="15" style="width: 80%;">
</textarea>
<button onClick="callVerifyProof();">Verify Proof</button>
<script src="index.js"></script>
</body>
</html>

30
wasm/index.js Normal file

File diff suppressed because one or more lines are too long

15
wasm/package.json Normal file
View File

@@ -0,0 +1,15 @@
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.16.4"
}
}

7
wasm/server.js Normal file
View File

@@ -0,0 +1,7 @@
var express = require('express');
var app = express();
express.static.mime.types['wasm'] = 'application/wasm';
app.use(express.static(__dirname + '/'));
port=8080
app.listen(8080);
console.log("server running at :8080")