mirror of
https://github.com/arnaucube/go-snark-study.git
synced 2026-02-02 17:26:41 +01:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
478006134d | ||
|
|
aec3022978 | ||
|
|
2461f86bda | ||
|
|
3308c3d94e | ||
| 2cbba4e007 | |||
|
|
469eabd451 | ||
|
|
41f7a3518a | ||
|
|
e98a97e9fe | ||
|
|
417cc92a97 | ||
|
|
0a162482ee | ||
|
|
662d92b697 | ||
|
|
f57599c091 | ||
|
|
e3cd35c1c9 | ||
|
|
fa91b9ffad | ||
|
|
a37361abf7 | ||
|
|
7b1a15df7f | ||
|
|
de5b60b826 | ||
|
|
165699b58f |
10
.travis.yml
Normal file
10
.travis.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- "1.12"
|
||||
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
|
||||
before_install: rm wasm/go-snark-wasm-wrapper.go
|
||||
|
||||
99
README.md
99
README.md
@@ -1,18 +1,21 @@
|
||||
# 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 [](https://goreportcard.com/report/github.com/arnaucube/go-snark-study) [](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
|
||||
- [](https://godoc.org/github.com/arnaucube/go-snark) zkSnark
|
||||
- [](https://godoc.org/github.com/arnaucube/go-snark/bn128) bn128 (more details: https://github.com/arnaucube/go-snark/tree/master/bn128)
|
||||
- [](https://godoc.org/github.com/arnaucube/go-snark/fields) Finite Fields operations
|
||||
- [](https://godoc.org/github.com/arnaucube/go-snark/r1csqap) R1CS to QAP (more details: https://github.com/arnaucube/go-snark/tree/master/r1csqap)
|
||||
- [](https://godoc.org/github.com/arnaucube/go-snark/circuitcompiler) Circuit Compiler
|
||||
- [](https://godoc.org/github.com/arnaucube/go-snark-study) zkSnark
|
||||
- [](https://godoc.org/github.com/arnaucube/go-snark-study/groth16) zkSnark Groth16
|
||||
- [](https://godoc.org/github.com/arnaucube/go-snark-study/bn128) bn128 (more details: https://github.com/arnaucube/go-snark-study/tree/master/bn128)
|
||||
- [](https://godoc.org/github.com/arnaucube/go-snark-study/fields) Finite Fields operations
|
||||
- [](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)
|
||||
- [](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
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
## Bn128
|
||||
[](https://godoc.org/github.com/arnaucube/go-snark/bn128) bn128
|
||||
[](https://godoc.org/github.com/arnaucube/go-snark-study/bn128) bn128
|
||||
Implementation of the bn128 pairing in Go.
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
8
circuitcompiler/circuit-test-1.circuit
Normal file
8
circuitcompiler/circuit-test-1.circuit
Normal 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
|
||||
7
circuitcompiler/circuit-test-2.circuit
Normal file
7
circuitcompiler/circuit-test-2.circuit
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
8
circuitexamples/import-example.circuit
Normal file
8
circuitexamples/import-example.circuit
Normal 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
|
||||
7
circuitexamples/imported-example.circuit
Normal file
7
circuitexamples/imported-example.circuit
Normal 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
|
||||
257
cli/main.go
257
cli/main.go
@@ -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
12
externalVerif/README.md
Normal 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)
|
||||
```
|
||||
8
externalVerif/circom-test/circuit.circom
Normal file
8
externalVerif/circom-test/circuit.circom
Normal file
@@ -0,0 +1,8 @@
|
||||
template Multiplier() {
|
||||
signal private input a;
|
||||
signal private input b;
|
||||
signal output c;
|
||||
c <== a*b;
|
||||
}
|
||||
|
||||
component main = Multiplier();
|
||||
74
externalVerif/circom-test/circuit.json
Normal file
74
externalVerif/circom-test/circuit.json
Normal 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
|
||||
}
|
||||
1
externalVerif/circom-test/input.json
Normal file
1
externalVerif/circom-test/input.json
Normal file
@@ -0,0 +1 @@
|
||||
{"a": 3, "b": 11}
|
||||
27
externalVerif/circom-test/proof.json
Normal file
27
externalVerif/circom-test/proof.json
Normal 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"
|
||||
}
|
||||
221
externalVerif/circom-test/proving_key.json
Normal file
221
externalVerif/circom-test/proving_key.json
Normal 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"
|
||||
]
|
||||
]
|
||||
}
|
||||
3
externalVerif/circom-test/public.json
Normal file
3
externalVerif/circom-test/public.json
Normal file
@@ -0,0 +1,3 @@
|
||||
[
|
||||
"33"
|
||||
]
|
||||
93
externalVerif/circom-test/verification_key.json
Normal file
93
externalVerif/circom-test/verification_key.json
Normal 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"
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
6
externalVerif/circom-test/witness.json
Normal file
6
externalVerif/circom-test/witness.json
Normal file
@@ -0,0 +1,6 @@
|
||||
[
|
||||
"1",
|
||||
"33",
|
||||
"3",
|
||||
"11"
|
||||
]
|
||||
90
externalVerif/circomVerifier.go
Normal file
90
externalVerif/circomVerifier.go
Normal 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
|
||||
}
|
||||
13
externalVerif/circomVerifier_test.go
Normal file
13
externalVerif/circomVerifier_test.go
Normal 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)
|
||||
}
|
||||
15
fields/fq.go
15
fields/fq.go
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
BIN
go-snark-cli
BIN
go-snark-cli
Binary file not shown.
2
go.mod
2
go.mod
@@ -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
305
groth16/groth16.go
Normal 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
107
groth16/groth16_test.go
Normal 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))
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
## R1CS to Quadratic Arithmetic Program
|
||||
[](https://godoc.org/github.com/arnaucube/go-snark/r1csqap) R1CS to QAP
|
||||
[](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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
117
snark.go
@@ -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
|
||||
|
||||
179
snark_test.go
179
snark_test.go
@@ -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
585
utils/base10parsers.go
Normal 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
562
utils/hexparsers.go
Normal 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
|
||||
}
|
||||
@@ -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'}
|
||||
```
|
||||
|
||||

|
||||

|
||||
|
||||
@@ -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
3
wasm/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
package-lock.json
|
||||
wasm_exec.js
|
||||
22
wasm/README.md
Normal file
22
wasm/README.md
Normal 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
|
||||
```
|
||||
246
wasm/go-snark-wasm-wrapper.go
Normal file
246
wasm/go-snark-wasm-wrapper.go
Normal 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
BIN
wasm/go-snark.wasm
Executable file
Binary file not shown.
20
wasm/index.html
Normal file
20
wasm/index.html
Normal 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
30
wasm/index.js
Normal file
File diff suppressed because one or more lines are too long
15
wasm/package.json
Normal file
15
wasm/package.json
Normal 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
7
wasm/server.js
Normal 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")
|
||||
Reference in New Issue
Block a user