7 Commits
0.0.1 ... 0.0.3

Author SHA1 Message Date
arnaucube
f57599c091 add Groth16 to cli 2019-06-10 15:12:07 +02:00
arnaucube
e3cd35c1c9 add Groth16 proof generation & verification 2019-06-10 13:07:09 +02:00
arnaucube
fa91b9ffad add Groth16 setup calculation 2019-06-10 11:43:59 +02:00
arnaucube
a37361abf7 add gitter button 2019-06-07 22:57:04 +02:00
arnaucube
7b1a15df7f add travis 2019-06-03 18:47:30 +02:00
arnaucube
de5b60b826 add allow import circuits in circuits language compiler 2019-05-30 21:39:00 +02:00
arnaucube
165699b58f circuitcompiler allow to call declared functions in circuits language 2019-05-25 04:11:39 +02:00
17 changed files with 1144 additions and 101 deletions

7
.travis.yml Normal file
View File

@@ -0,0 +1,7 @@
language: go
go:
- "1.12"
env:
- GO111MODULE=on

View File

@@ -1,18 +1,21 @@
# go-snark [![Go Report Card](https://goreportcard.com/badge/github.com/arnaucube/go-snark)](https://goreportcard.com/report/github.com/arnaucube/go-snark) # go-snark [![Go Report Card](https://goreportcard.com/badge/github.com/arnaucube/go-snark)](https://goreportcard.com/report/github.com/arnaucube/go-snark) [![Build Status](https://travis-ci.org/arnaucube/go-snark.svg?branch=master)](https://travis-ci.org/arnaucube/go-snark) [![Gitter](https://badges.gitter.im/go-snark/community.svg)](https://gitter.im/go-snark/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
zkSNARK library implementation in Go 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 - `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 - `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 ## 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. 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 to understand the concepts. Do not use in production.
Not finished, implementing this in my free time to understand it better, so I don't have much time. 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) : 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) :
1. compile circuuit
0. write circuit
1. compile circuit
2. generate trusted setup 2. generate trusted setup
3. calculate witness 3. calculate witness
4. generate proofs 4. generate proofs
@@ -31,16 +34,17 @@ Minimal complete flow implementation:
- [x] verify proofs with BN128 pairing - [x] verify proofs with BN128 pairing
Improvements from the minimal implementation: Improvements from the minimal implementation:
- [ ] allow `import` in circuits language - [x] allow to call functions in circuits language
- [x] allow `import` in circuits language
- [ ] allow `for` in circuits language - [ ] allow `for` in circuits language
- [ ] code to flat code (improve circuit compiler)
- [ ] move witness values calculation outside the setup phase - [ ] move witness values calculation outside the setup phase
- [ ] Groth16 - [x] Groth16
- [ ] multiple optimizations - [ ] multiple optimizations
## Usage ## Usage
- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark?status.svg)](https://godoc.org/github.com/arnaucube/go-snark) zkSnark - [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark?status.svg)](https://godoc.org/github.com/arnaucube/go-snark) zkSnark
- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/groth16?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/groth16) zkSnark Groth16
- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/bn128?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/bn128) bn128 (more details: https://github.com/arnaucube/go-snark/tree/master/bn128) - [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/bn128?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/bn128) bn128 (more details: https://github.com/arnaucube/go-snark/tree/master/bn128)
- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/fields?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/fields) Finite Fields operations - [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/fields?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/fields) Finite Fields operations
- [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/r1csqap?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/r1csqap) R1CS to QAP (more details: https://github.com/arnaucube/go-snark/tree/master/r1csqap) - [![GoDoc](https://godoc.org/github.com/arnaucube/go-snark/r1csqap?status.svg)](https://godoc.org/github.com/arnaucube/go-snark/r1csqap) R1CS to QAP (more details: https://github.com/arnaucube/go-snark/tree/master/r1csqap)
@@ -54,9 +58,13 @@ In this example we will follow the equation example from [Vitalik](https://mediu
#### Compile circuit #### Compile circuit
Having a circuit file `test.circuit`: Having a circuit file `test.circuit`:
``` ```
func test(private s0, public s1): func exp3(private a):
s2 = s0 * s0 b = a * a
s3 = s2 * s0 c = a * b
return c
func main(private s0, public s1):
s3 = exp3(s0)
s4 = s3 + s0 s4 = s3 + s0
s5 = s4 + 5 s5 = s4 + 5
equals(s1, s5) equals(s1, s5)
@@ -105,6 +113,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. 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 ### Library usage
@@ -112,9 +130,13 @@ Example:
```go ```go
// compile circuit and get the R1CS // compile circuit and get the R1CS
flatCode := ` flatCode := `
func test(private s0, public s1): func exp3(private a):
s2 = s0 * s0 b = a * a
s3 = s2 * s0 c = a * b
return c
func main(private s0, public s1):
s3 = exp3(s0)
s4 = s3 + s0 s4 = s3 + s0
s5 = s4 + 5 s5 = s4 + 5
equals(s1, s5) equals(s1, s5)
@@ -147,8 +169,8 @@ a, b, c := circuit.GenerateR1CS()
/* /*
now we have the R1CS from the circuit: 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]] 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 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]] 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]] 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]]
*/ */
@@ -171,6 +193,11 @@ assert.True(t, VerifyProof(*circuit, setup, proof, publicSignalsVerif, true))
``` ```
## 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 ## Test
``` ```

View File

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

View File

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

View File

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

View File

@@ -1,11 +1,13 @@
package circuitcompiler package circuitcompiler
import ( import (
"bufio"
"errors" "errors"
"fmt" "fmt"
"io" "io"
"os" "os"
"regexp" "regexp"
"strconv"
"strings" "strings"
) )
@@ -68,6 +70,12 @@ func (p *Parser) parseLine() (*Constraint, error) {
if err != nil { if err != nil {
return c, err 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 ( ) // read string inside ( )
rgx := regexp.MustCompile(`\((.*?)\)`) rgx := regexp.MustCompile(`\((.*?)\)`)
insideParenthesis := rgx.FindStringSubmatch(line) insideParenthesis := rgx.FindStringSubmatch(line)
@@ -105,20 +113,60 @@ func (p *Parser) parseLine() (*Constraint, error) {
c.V2 = params[1] c.V2 = params[1]
return c, nil return c, nil
} }
// if c.Literal == "out" { if c.Literal == "return" {
// // TODO _, varToReturn := p.scanIgnoreWhitespace()
// return c, nil 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 = _, lit = p.scanIgnoreWhitespace() // skip =
c.Literal += lit c.Literal += lit
// v1 // v1
_, lit = p.scanIgnoreWhitespace() _, 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.V1 = lit
c.Literal += lit c.Literal += lit
// operator // operator
_, lit = p.scanIgnoreWhitespace() _, lit = p.scanIgnoreWhitespace()
if lit == "(" {
panic(errors.New("using not declared function"))
}
c.Op = lit c.Op = lit
c.Literal += lit c.Literal += lit
// v2 // v2
@@ -150,39 +198,67 @@ func addToArrayIfNotExist(arr []string, elem string) []string {
return arr 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 // Parse parses the lines and returns the compiled Circuit
func (p *Parser) Parse() (*Circuit, error) { func (p *Parser) Parse() (*Circuit, error) {
circuit := &Circuit{} // funcsMap is a map holding the functions names and it's content as Circuit
circuit.Signals = append(circuit.Signals, "one") circuits = make(map[string]*Circuit)
mainExist := false
circuits["main"] = &Circuit{}
callsCount := 0
circuits["main"].Signals = append(circuits["main"].Signals, "one")
nInputs := 0 nInputs := 0
currCircuit := ""
for { for {
constraint, err := p.parseLine() constraint, err := p.parseLine()
if err != nil { if err != nil {
break break
} }
if constraint.Literal == "func" { 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 // one constraint for each input
for _, in := range constraint.PublicInputs { for _, in := range constraint.PublicInputs {
newConstr := &Constraint{ newConstr := &Constraint{
Op: "in", Op: "in",
Out: in, Out: in,
} }
circuit.Constraints = append(circuit.Constraints, *newConstr) circuits[currCircuit].Constraints = append(circuits[currCircuit].Constraints, *newConstr)
nInputs++ nInputs++
circuit.Signals = addToArrayIfNotExist(circuit.Signals, in) circuits[currCircuit].Signals = addToArrayIfNotExist(circuits[currCircuit].Signals, in)
circuit.NPublic++ circuits[currCircuit].NPublic++
} }
for _, in := range constraint.PrivateInputs { for _, in := range constraint.PrivateInputs {
newConstr := &Constraint{ newConstr := &Constraint{
Op: "in", Op: "in",
Out: in, Out: in,
} }
circuit.Constraints = append(circuit.Constraints, *newConstr) circuits[currCircuit].Constraints = append(circuits[currCircuit].Constraints, *newConstr)
nInputs++ nInputs++
circuit.Signals = addToArrayIfNotExist(circuit.Signals, in) circuits[currCircuit].Signals = addToArrayIfNotExist(circuits[currCircuit].Signals, in)
} }
circuit.PublicInputs = constraint.PublicInputs circuits[currCircuit].PublicInputs = constraint.PublicInputs
circuit.PrivateInputs = constraint.PrivateInputs circuits[currCircuit].PrivateInputs = constraint.PrivateInputs
continue continue
} }
if constraint.Literal == "equals" { if constraint.Literal == "equals" {
@@ -193,7 +269,7 @@ func (p *Parser) Parse() (*Circuit, error) {
Out: constraint.V1, Out: constraint.V1,
Literal: "equals(" + constraint.V1 + ", " + constraint.V2 + "): " + constraint.V1 + "==" + constraint.V2 + " * 1", 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{ constr2 := &Constraint{
Op: "*", Op: "*",
V1: constraint.V1, V1: constraint.V1,
@@ -201,42 +277,73 @@ func (p *Parser) Parse() (*Circuit, error) {
Out: constraint.V2, Out: constraint.V2,
Literal: "equals(" + constraint.V1 + ", " + constraint.V2 + "): " + constraint.V2 + "==" + constraint.V1 + " * 1", 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 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) isVal, _ := isValue(constraint.V1)
if !isVal { if !isVal {
circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V1) circuits[currCircuit].Signals = addToArrayIfNotExist(circuits[currCircuit].Signals, constraint.V1)
} }
isVal, _ = isValue(constraint.V2) isVal, _ = isValue(constraint.V2)
if !isVal { if !isVal {
circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V2) circuits[currCircuit].Signals = addToArrayIfNotExist(circuits[currCircuit].Signals, constraint.V2)
} }
// if constraint.Out == "out" { circuits[currCircuit].Signals = addToArrayIfNotExist(circuits[currCircuit].Signals, constraint.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)
// }
} }
circuit.NVars = len(circuit.Signals) circuits["main"].NVars = len(circuits["main"].Signals)
circuit.NSignals = len(circuit.Signals) circuits["main"].NSignals = len(circuits["main"].Signals)
return circuit, nil if mainExist == false {
return circuits["main"], errors.New("No 'main' func declared")
}
return circuits["main"], nil
} }
func copyArray(in []string) []string { // tmp func copyArray(in []string) []string { // tmp
var out []string var out []string

View File

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

View File

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

View File

@@ -13,6 +13,7 @@ import (
snark "github.com/arnaucube/go-snark" snark "github.com/arnaucube/go-snark"
"github.com/arnaucube/go-snark/circuitcompiler" "github.com/arnaucube/go-snark/circuitcompiler"
"github.com/arnaucube/go-snark/groth16"
"github.com/arnaucube/go-snark/r1csqap" "github.com/arnaucube/go-snark/r1csqap"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
@@ -48,12 +49,37 @@ var commands = []cli.Command{
Usage: "verify the snark proofs", Usage: "verify the snark proofs",
Action: VerifyProofs, 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() { func main() {
app := cli.NewApp() app := cli.NewApp()
app.Name = "go-snarks-cli" app.Name = "go-snarks-cli"
app.Version = "0.0.1-alpha" app.Version = "0.0.3-alpha"
app.Flags = []cli.Flag{ app.Flags = []cli.Flag{
cli.StringFlag{Name: "config"}, cli.StringFlag{Name: "config"},
} }
@@ -322,3 +348,162 @@ func VerifyProofs(context *cli.Context) error {
} }
return nil 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, 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 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 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(circuit, trustedsetup, proof, publicSignals, true)
if !verified {
fmt.Println("ERROR: proofs not verified")
} else {
fmt.Println("Proofs verified")
}
return nil
}

View File

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

View File

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

Binary file not shown.

302
groth16/groth16.go Normal file
View File

@@ -0,0 +1,302 @@
// implementation of https://eprint.iacr.org/2016/260.pdf
package groth16
import (
"fmt"
"math/big"
"github.com/arnaucube/go-snark/bn128"
"github.com/arnaucube/go-snark/circuitcompiler"
"github.com/arnaucube/go-snark/fields"
"github.com/arnaucube/go-snark/r1csqap"
)
// 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 struct { // Proving Key
BACDelta [][3]*big.Int // {( βui(x)+αvi(x)+wi(x) ) / γ } from 0 to l
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 l+1 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 l+1 to m
}
PowersTauDelta [][3]*big.Int // powers of τ encrypted in G1 curve, divided by δ
}
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
}
}
}
// 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 l+1 to m in G1
setup.Pk.G1.BACGamma = append(setup.Pk.G1.BACGamma, g1bt)
// G2.BACGamma: {( βui(x)+αvi(x)+wi(x) ) / δ } from l+1 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 0 to l
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, setup Setup, 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(setup.Pk.G1.At[i], w[i]))
piBG1 = Utils.Bn.G1.Add(piBG1, Utils.Bn.G1.MulScalar(setup.Pk.G1.BACGamma[i], w[i]))
proof.PiB = Utils.Bn.G2.Add(proof.PiB, Utils.Bn.G2.MulScalar(setup.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(setup.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, setup.Pk.G1.Alpha)
deltaR := Utils.Bn.G1.MulScalar(setup.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, setup.Pk.G1.Beta)
proof.PiB = Utils.Bn.G2.Add(proof.PiB, setup.Pk.G2.Beta)
deltaSG1 := Utils.Bn.G1.MulScalar(setup.Pk.G1.Delta, s)
piBG1 = Utils.Bn.G1.Add(piBG1, deltaSG1)
deltaSG2 := Utils.Bn.G2.MulScalar(setup.Pk.G2.Delta, s)
proof.PiB = Utils.Bn.G2.Add(proof.PiB, deltaSG2)
hx := Utils.PF.DivisorPolynomial(px, setup.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(setup.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(setup.Pk.G1.Delta, negRS))
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 {
icPubl := setup.Vk.IC[0]
for i := 0; i < len(publicSignals); i++ {
icPubl = Utils.Bn.G1.Add(icPubl, Utils.Bn.G1.MulScalar(setup.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(setup.Vk.G1.Alpha, setup.Vk.G2.Beta),
Utils.Bn.Fq12.Mul(
Utils.Bn.Pairing(icPubl, setup.Vk.G2.Gamma),
Utils.Bn.Pairing(proof.PiC, setup.Vk.G2.Delta)))) {
if debug {
fmt.Println("❌ groth16 verification not passed")
}
return false
}
if debug {
fmt.Println("✓ groth16 verification passed")
}
return true
}

107
groth16/groth16_test.go Normal file
View File

@@ -0,0 +1,107 @@
package groth16
import (
"bytes"
"fmt"
"math/big"
"strings"
"testing"
"time"
"github.com/arnaucube/go-snark/circuitcompiler"
"github.com/arnaucube/go-snark/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, 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(*circuit, setup, 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, false))
}

View File

@@ -1,3 +1,5 @@
// implementation of https://eprint.iacr.org/2013/879.pdf
package snark package snark
import ( import (
@@ -289,7 +291,9 @@ func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publ
pairingPiaVa := Utils.Bn.Pairing(proof.PiA, setup.Vk.Vka) pairingPiaVa := Utils.Bn.Pairing(proof.PiA, setup.Vk.Vka)
pairingPiapG2 := Utils.Bn.Pairing(proof.PiAp, Utils.Bn.G2.G) pairingPiapG2 := Utils.Bn.Pairing(proof.PiAp, Utils.Bn.G2.G)
if !Utils.Bn.Fq12.Equal(pairingPiaVa, pairingPiapG2) { if !Utils.Bn.Fq12.Equal(pairingPiaVa, pairingPiapG2) {
if debug {
fmt.Println("❌ e(piA, Va) == e(piA', g2), valid knowledge commitment for A") fmt.Println("❌ e(piA, Va) == e(piA', g2), valid knowledge commitment for A")
}
return false return false
} }
if debug { if debug {
@@ -300,7 +304,9 @@ func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publ
pairingVbPib := Utils.Bn.Pairing(setup.Vk.Vkb, proof.PiB) pairingVbPib := Utils.Bn.Pairing(setup.Vk.Vkb, proof.PiB)
pairingPibpG2 := Utils.Bn.Pairing(proof.PiBp, Utils.Bn.G2.G) pairingPibpG2 := Utils.Bn.Pairing(proof.PiBp, Utils.Bn.G2.G)
if !Utils.Bn.Fq12.Equal(pairingVbPib, pairingPibpG2) { if !Utils.Bn.Fq12.Equal(pairingVbPib, pairingPibpG2) {
if debug {
fmt.Println("❌ e(Vb, piB) == e(piB', g2), valid knowledge commitment for B") fmt.Println("❌ e(Vb, piB) == e(piB', g2), valid knowledge commitment for B")
}
return false return false
} }
if debug { if debug {
@@ -311,7 +317,9 @@ func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publ
pairingPicVc := Utils.Bn.Pairing(proof.PiC, setup.Vk.Vkc) pairingPicVc := Utils.Bn.Pairing(proof.PiC, setup.Vk.Vkc)
pairingPicpG2 := Utils.Bn.Pairing(proof.PiCp, Utils.Bn.G2.G) pairingPicpG2 := Utils.Bn.Pairing(proof.PiCp, Utils.Bn.G2.G)
if !Utils.Bn.Fq12.Equal(pairingPicVc, pairingPicpG2) { if !Utils.Bn.Fq12.Equal(pairingPicVc, pairingPicpG2) {
if debug {
fmt.Println("❌ e(piC, Vc) == e(piC', g2), valid knowledge commitment for C") fmt.Println("❌ e(piC, Vc) == e(piC', g2), valid knowledge commitment for C")
}
return false return false
} }
if debug { if debug {
@@ -330,7 +338,9 @@ func VerifyProof(circuit circuitcompiler.Circuit, setup Setup, proof Proof, publ
Utils.Bn.Fq12.Mul( Utils.Bn.Fq12.Mul(
Utils.Bn.Pairing(proof.PiH, setup.Vk.Vkz), Utils.Bn.Pairing(proof.PiH, setup.Vk.Vkz),
Utils.Bn.Pairing(proof.PiC, Utils.Bn.G2.G))) { Utils.Bn.Pairing(proof.PiC, Utils.Bn.G2.G))) {
if debug {
fmt.Println("❌ e(Vkx+piA, piB) == e(piH, Vkz) * e(piC, g2), QAP disibility checked") fmt.Println("❌ e(Vkx+piA, piB) == e(piH, Vkz) * e(piC, g2), QAP disibility checked")
}
return false return false
} }
if debug { if debug {

View File

@@ -9,17 +9,17 @@ import (
"time" "time"
"github.com/arnaucube/go-snark/circuitcompiler" "github.com/arnaucube/go-snark/circuitcompiler"
"github.com/arnaucube/go-snark/groth16"
"github.com/arnaucube/go-snark/r1csqap" "github.com/arnaucube/go-snark/r1csqap"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestZkFromFlatCircuitCode(t *testing.T) { func TestGroth16MinimalFlow(t *testing.T) {
// compile circuit and get the R1CS fmt.Println("testing Groth16 minimal flow")
// circuit function // circuit function
// y = x^3 + x + 5 // y = x^3 + x + 5
flatCode := ` code := `
func test(private s0, public s1): func main(private s0, public s1):
s2 = s0 * s0 s2 = s0 * s0
s3 = s2 * s0 s3 = s2 * s0
s4 = s3 + s0 s4 = s3 + s0
@@ -27,11 +27,122 @@ func TestZkFromFlatCircuitCode(t *testing.T) {
equals(s1, s5) equals(s1, s5)
out = 1 * 1 out = 1 * 1
` `
fmt.Print("\nflat code of the circuit:") fmt.Print("\ncode of the circuit:")
fmt.Println(flatCode)
// parse the code // 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, 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(*circuit, setup, 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(*circuit, setup, 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() circuit, err := parser.Parse()
assert.Nil(t, err) assert.Nil(t, err)
// fmt.Println("\ncircuit data:", circuit) // fmt.Println("\ncircuit data:", circuit)
@@ -47,8 +158,8 @@ func TestZkFromFlatCircuitCode(t *testing.T) {
w, err := circuit.CalculateWitness(privateInputs, publicSignals) w, err := circuit.CalculateWitness(privateInputs, publicSignals)
assert.Nil(t, err) assert.Nil(t, err)
// flat code to R1CS // code to R1CS
fmt.Println("\ngenerating R1CS from flat code") fmt.Println("\ngenerating R1CS from code")
a, b, c := circuit.GenerateR1CS() a, b, c := circuit.GenerateR1CS()
fmt.Println("\nR1CS:") fmt.Println("\nR1CS:")
fmt.Println("a:", a) fmt.Println("a:", a)
@@ -128,20 +239,20 @@ func TestZkFromFlatCircuitCode(t *testing.T) {
// check that with another public input the verification returns false // check that with another public input the verification returns false
bOtherWrongPublic := big.NewInt(int64(34)) bOtherWrongPublic := big.NewInt(int64(34))
wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic} wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic}
assert.True(t, !VerifyProof(*circuit, setup, proof, wrongPublicSignalsVerif, true)) assert.True(t, !VerifyProof(*circuit, setup, proof, wrongPublicSignalsVerif, false))
} }
func TestZkMultiplication(t *testing.T) { func TestZkMultiplication(t *testing.T) {
flatCode := ` code := `
func test(private a, private b, public c): func main(private a, private b, public c):
d = a * b d = a * b
equals(c, d) equals(c, d)
out = 1 * 1 out = 1 * 1
` `
fmt.Println("flat code", flatCode) fmt.Println("code", code)
// parse the code // parse the code
parser := circuitcompiler.NewParser(strings.NewReader(flatCode)) parser := circuitcompiler.NewParser(strings.NewReader(code))
circuit, err := parser.Parse() circuit, err := parser.Parse()
assert.Nil(t, err) assert.Nil(t, err)
@@ -155,8 +266,8 @@ func TestZkMultiplication(t *testing.T) {
w, err := circuit.CalculateWitness(privateInputs, publicSignals) w, err := circuit.CalculateWitness(privateInputs, publicSignals)
assert.Nil(t, err) assert.Nil(t, err)
// flat code to R1CS // code to R1CS
fmt.Println("\ngenerating R1CS from flat code") fmt.Println("\ngenerating R1CS from code")
a, b, c := circuit.GenerateR1CS() a, b, c := circuit.GenerateR1CS()
fmt.Println("\nR1CS:") fmt.Println("\nR1CS:")
fmt.Println("a:", a) fmt.Println("a:", a)
@@ -236,14 +347,14 @@ func TestZkMultiplication(t *testing.T) {
// check that with another public input the verification returns false // check that with another public input the verification returns false
bOtherWrongPublic := big.NewInt(int64(11)) bOtherWrongPublic := big.NewInt(int64(11))
wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic} wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic}
assert.True(t, !VerifyProof(*circuit, setup, proof, wrongPublicSignalsVerif, true)) assert.True(t, !VerifyProof(*circuit, setup, proof, wrongPublicSignalsVerif, false))
} }
func TestMinimalFlow(t *testing.T) { func TestMinimalFlow(t *testing.T) {
// circuit function // circuit function
// y = x^3 + x + 5 // y = x^3 + x + 5
flatCode := ` code := `
func test(private s0, public s1): func main(private s0, public s1):
s2 = s0 * s0 s2 = s0 * s0
s3 = s2 * s0 s3 = s2 * s0
s4 = s3 + s0 s4 = s3 + s0
@@ -251,11 +362,11 @@ func TestMinimalFlow(t *testing.T) {
equals(s1, s5) equals(s1, s5)
out = 1 * 1 out = 1 * 1
` `
fmt.Print("\nflat code of the circuit:") fmt.Print("\ncode of the circuit:")
fmt.Println(flatCode) fmt.Println(code)
// parse the code // parse the code
parser := circuitcompiler.NewParser(strings.NewReader(flatCode)) parser := circuitcompiler.NewParser(strings.NewReader(code))
circuit, err := parser.Parse() circuit, err := parser.Parse()
assert.Nil(t, err) assert.Nil(t, err)
@@ -268,8 +379,8 @@ func TestMinimalFlow(t *testing.T) {
w, err := circuit.CalculateWitness(privateInputs, publicSignals) w, err := circuit.CalculateWitness(privateInputs, publicSignals)
assert.Nil(t, err) assert.Nil(t, err)
// flat code to R1CS // code to R1CS
fmt.Println("\ngenerating R1CS from flat code") fmt.Println("\ngenerating R1CS from code")
a, b, c := circuit.GenerateR1CS() a, b, c := circuit.GenerateR1CS()
fmt.Println("\nR1CS:") fmt.Println("\nR1CS:")
fmt.Println("a:", a) fmt.Println("a:", a)
@@ -325,5 +436,5 @@ func TestMinimalFlow(t *testing.T) {
// check that with another public input the verification returns false // check that with another public input the verification returns false
bOtherWrongPublic := big.NewInt(int64(34)) bOtherWrongPublic := big.NewInt(int64(34))
wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic} wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic}
assert.True(t, !VerifyProof(*circuit, setup, proof, wrongPublicSignalsVerif, true)) assert.True(t, !VerifyProof(*circuit, setup, proof, wrongPublicSignalsVerif, false))
} }

View File

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