diff --git a/.idea/go-snark.iml b/.idea/go-snark.iml
new file mode 100644
index 0000000..c956989
--- /dev/null
+++ b/.idea/go-snark.iml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..28a804d
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..b9cbca6
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..405f86d
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,552 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ arnaucube
+ oneConst
+ getmain
+ opera
+
+
+ mottla
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ file://$PROJECT_DIR$/circuitcompiler/Programm.go
+ 75
+
+
+
+
+ file://$PROJECT_DIR$/circuitcompiler/Programm.go
+ 82
+
+
+
+
+ file://$PROJECT_DIR$/circuitcompiler/Programm.go
+ 66
+
+
+
+
+ file://$PROJECT_DIR$/circuitcompiler/parser.go
+ 60
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index c4c46c7..8c1794f 100644
--- a/README.md
+++ b/README.md
@@ -7,25 +7,27 @@ zkSNARK library implementation in Go
- `Pinocchio: Nearly practical verifiable computation`, Bryan Parno, Craig Gentry, Jon Howell, Mariana Raykova https://eprint.iacr.org/2013/279.pdf
## Caution, Warning
+UNDER CONSTRUCTION!
+
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.
-Not finished, implementing this in my free time to understand it better, so I don't have much time.
+This forked aims to extend its functionalities s.t. one can prove set-membership in zero knowledge.
Current implementation status:
- [x] Finite Fields (1, 2, 6, 12) operations
- [x] G1 and G2 curve operations
-- [x] BN128 Pairing
+- [x] BN128 Pairing (to be replaced with less unsecure curve)
- [x] circuit code compiler
- - [ ] code to flat code (improve circuit compiler)
+ - [ ] code to flat code (improve circuit compiler) (in progress)
- [x] flat code compiler
-- [x] circuit to R1CS
+- [x] circuit to R1CS with gate reduction optimisation
- [x] polynomial operations
- [x] R1CS to QAP
- [x] generate trusted setup
- [x] generate proofs
- [x] verify proofs with BN128 pairing
-- [ ] move witness calculation outside the setup phase
-- [ ] Groth16
+- [x] move witness calculation outside the setup phase
+- [ ] Groth16 (in progress)
- [ ] multiple optimizations
diff --git a/bn128/bn128.go b/bn128/bn128.go
index ebef4ee..77c1b9c 100644
--- a/bn128/bn128.go
+++ b/bn128/bn128.go
@@ -4,7 +4,7 @@ import (
"errors"
"math/big"
- "github.com/arnaucube/go-snark/fields"
+ "github.com/mottla/go-snark/fields"
)
// Bn128 is the data structure of the BN128
diff --git a/bn128/g1.go b/bn128/g1.go
index 0f5b9e0..e7a8b56 100644
--- a/bn128/g1.go
+++ b/bn128/g1.go
@@ -3,7 +3,7 @@ package bn128
import (
"math/big"
- "github.com/arnaucube/go-snark/fields"
+ "github.com/mottla/go-snark/fields"
)
type G1 struct {
diff --git a/bn128/g2.go b/bn128/g2.go
index 0c05a3a..9146500 100644
--- a/bn128/g2.go
+++ b/bn128/g2.go
@@ -3,7 +3,7 @@ package bn128
import (
"math/big"
- "github.com/arnaucube/go-snark/fields"
+ "github.com/mottla/go-snark/fields"
)
type G2 struct {
diff --git a/circuitcompiler/Programm.go b/circuitcompiler/Programm.go
new file mode 100644
index 0000000..0369bc9
--- /dev/null
+++ b/circuitcompiler/Programm.go
@@ -0,0 +1,382 @@
+package circuitcompiler
+
+import (
+ "fmt"
+ "github.com/mottla/go-snark/r1csqap"
+ "math/big"
+)
+
+type Program struct {
+ functions map[string]*Circuit
+ signals []string
+ globalInputs []*Constraint
+ R1CS struct {
+ A [][]*big.Int
+ B [][]*big.Int
+ C [][]*big.Int
+ }
+}
+
+func (p *Program) PrintContraintTrees() {
+ for k, v := range p.functions {
+ fmt.Println(k)
+ PrintTree(v.root)
+ }
+}
+
+func (p *Program) BuildConstraintTrees() {
+
+ functionRootMap := make(map[string]*gate)
+ for _, circuit := range p.functions {
+ circuit.addConstraint(p.oneConstraint())
+ fName := composeNewFunction(circuit.Name, circuit.Inputs)
+ root := &gate{value: circuit.constraintMap[fName]}
+ functionRootMap[fName] = root
+ circuit.root = root
+ }
+
+ for _, circuit := range p.functions {
+
+ buildTree(circuit.constraintMap, circuit.root)
+
+ }
+
+ return
+
+}
+
+func buildTree(con map[string]*Constraint, g *gate) {
+ if _, ex := con[g.value.Out]; ex {
+ if g.OperationType()&(IN|CONST) != 0 {
+ return
+ }
+ } else {
+ panic(fmt.Sprintf("undefined variable %s", g.value.Out))
+ }
+ if g.OperationType() == FUNC {
+ g.funcInputs = []*gate{}
+ for _, in := range g.value.Inputs {
+ if constr, ex := con[in]; ex {
+ newGate := &gate{value: constr}
+ g.funcInputs = append(g.funcInputs, newGate)
+ buildTree(con, newGate)
+ } else {
+ panic(fmt.Sprintf("undefined value %s", g.value.V1))
+ }
+ }
+ return
+ }
+ if constr, ex := con[g.value.V1]; ex {
+ g.addLeft(constr)
+ buildTree(con, g.left)
+ } else {
+ panic(fmt.Sprintf("undefined value %s", g.value.V1))
+ }
+
+ if constr, ex := con[g.value.V2]; ex {
+ g.addRight(constr)
+ buildTree(con, g.right)
+ } else {
+ panic(fmt.Sprintf("undefined value %s", g.value.V2))
+ }
+}
+
+func (p *Program) ReduceCombinedTree() (orderedmGates []gate) {
+ mGatesUsed := make(map[string]bool)
+ orderedmGates = []gate{}
+ functionRootMap := make(map[string]*gate)
+ for k, v := range p.functions {
+ functionRootMap[k] = v.root
+ }
+
+ functionRenamer := func(c *Constraint) *gate {
+
+ if c.Op != FUNC {
+ panic("not a function")
+ }
+ if b, name, in := isFunction(c.Out); b {
+
+ if k, v := p.functions[name]; v {
+ //fmt.Println("unrenamed thing")
+ //PrintTree(k.root)
+ k.renameInputs(in)
+ //fmt.Println("renamed thing")
+ //PrintTree(k.root)
+ return k.root
+ }
+ } else {
+ panic("not a function dude")
+ }
+ return nil
+ }
+
+ traverseCombinedMultiplicationGates(p.getMainCircut().root, mGatesUsed, &orderedmGates, functionRootMap, functionRenamer, false, false)
+
+ //for _, g := range mGates {
+ // orderedmGates[len(orderedmGates)-1-g.index] = g
+ //}
+
+ return orderedmGates
+}
+
+func traverseCombinedMultiplicationGates(root *gate, mGatesUsed map[string]bool, orderedmGates *[]gate, functionRootMap map[string]*gate, functionRenamer func(c *Constraint) *gate, negate bool, inverse bool) {
+ //if root == nil {
+ // return
+ //}
+ if root.OperationType() == FUNC {
+ //if a input has already been built, we let this subroutine know
+ newMap := make(map[string]bool)
+ for _, in := range root.funcInputs {
+
+ if _, ex := mGatesUsed[in.value.Out]; ex {
+ newMap[in.value.Out] = true
+ } else {
+ traverseCombinedMultiplicationGates(in, mGatesUsed, orderedmGates, functionRootMap, functionRenamer, negate, inverse)
+ }
+ }
+ //mGatesUsed[root.value.Out] = true
+ traverseCombinedMultiplicationGates(functionRenamer(root.value), newMap, orderedmGates, functionRootMap, functionRenamer, negate, inverse)
+ } else {
+ if _, alreadyComputed := mGatesUsed[root.value.V1]; !alreadyComputed && root.OperationType()&(IN|CONST) == 0 {
+ traverseCombinedMultiplicationGates(root.left, mGatesUsed, orderedmGates, functionRootMap, functionRenamer, negate, inverse)
+ }
+
+ if _, alreadyComputed := mGatesUsed[root.value.V2]; !alreadyComputed && root.OperationType()&(IN|CONST) == 0 {
+ traverseCombinedMultiplicationGates(root.right, mGatesUsed, orderedmGates, functionRootMap, functionRenamer, Xor(negate, root.value.negate), Xor(inverse, root.value.invert))
+ }
+ }
+
+ if root.OperationType() == MULTIPLY {
+
+ root.leftIns = make(map[string]int)
+ collectAtomsInSubtree(root.left, root.leftIns, functionRootMap, negate, inverse)
+ root.rightIns = make(map[string]int)
+ collectAtomsInSubtree(root.right, root.rightIns, functionRootMap, Xor(negate, root.value.negate), Xor(inverse, root.value.invert))
+ root.index = len(mGatesUsed)
+ mGatesUsed[root.value.Out] = true
+ rootGate := cloneGate(root)
+ *orderedmGates = append(*orderedmGates, *rootGate)
+ }
+
+ //TODO optimize if output is not a multipication gate
+}
+
+//copies a gate neglecting its references to other gates
+func cloneGate(in *gate) (out *gate) {
+ constr := &Constraint{Inputs: in.value.Inputs, Out: in.value.Out, Op: in.value.Op, invert: in.value.invert, negate: in.value.negate, V2: in.value.V2, V1: in.value.V1}
+ nRightins := make(map[string]int)
+ nLeftInst := make(map[string]int)
+ for k, v := range in.rightIns {
+ nRightins[k] = v
+ }
+ for k, v := range in.leftIns {
+ nLeftInst[k] = v
+ }
+ return &gate{value: constr, leftIns: nLeftInst, rightIns: nRightins, index: in.index}
+}
+
+func (p *Program) getMainCircut() *Circuit {
+ return p.functions["main"]
+}
+
+func (p *Program) addGlobalInput(c *Constraint) {
+ p.globalInputs = append(p.globalInputs, c)
+}
+
+func NewProgramm() *Program {
+ return &Program{functions: map[string]*Circuit{}, signals: []string{}, globalInputs: []*Constraint{{Op: CONST, Out: "one"}}}
+}
+
+func (p *Program) oneConstraint() *Constraint {
+ if p.globalInputs[0].Out != "one" {
+ panic("'one' should be first global input")
+ }
+ return p.globalInputs[0]
+}
+
+func (p *Program) addSignal(name string) {
+ p.signals = append(p.signals, name)
+}
+
+func (p *Program) addFunction(constraint *Constraint) (c *Circuit) {
+ name := constraint.Out
+ fmt.Println("try to add function ", name)
+
+ b, name2, _ := isFunction(name)
+ if !b {
+ panic(fmt.Sprintf("not a function: %v", constraint))
+ }
+ name = name2
+
+ if _, ex := p.functions[name]; ex {
+ panic("function already declared")
+ }
+
+ c = newCircuit(name)
+
+ p.functions[name] = c
+
+ //if constraint.Literal == "main" {
+ for _, in := range constraint.Inputs {
+ newConstr := &Constraint{
+ Op: IN,
+ Out: in,
+ }
+ if name == "main" {
+ p.addGlobalInput(newConstr)
+ }
+ c.addConstraint(newConstr)
+ }
+
+ c.Inputs = constraint.Inputs
+ return
+
+}
+
+// GenerateR1CS generates the R1CS polynomials from the Circuit
+func (p *Program) GenerateReducedR1CS(mGates []gate) (a, b, c [][]*big.Int) {
+ // from flat code to R1CS
+
+ offset := len(p.globalInputs)
+ // one + in1 +in2+... + gate1 + gate2 .. + out
+ size := offset + len(mGates)
+ indexMap := make(map[string]int)
+
+ //circ.Signals = []string{"one"}
+ for i, v := range p.globalInputs {
+ indexMap[v.Out] = i
+ //circ.Signals = append(circ.Signals, v)
+
+ }
+ for i, v := range mGates {
+ indexMap[v.value.Out] = i + offset
+ //circ.Signals = append(circ.Signals, v.value.Out)
+ }
+ //circ.NVars = len(circ.Signals)
+ //circ.NSignals = len(circ.Signals)
+
+ for _, gate := range mGates {
+
+ if gate.OperationType() == MULTIPLY {
+ aConstraint := r1csqap.ArrayOfBigZeros(size)
+ bConstraint := r1csqap.ArrayOfBigZeros(size)
+ cConstraint := r1csqap.ArrayOfBigZeros(size)
+
+ for leftInput, val := range gate.leftIns {
+ insertVar3(aConstraint, val, leftInput, indexMap[leftInput])
+ }
+ for rightInput, val := range gate.rightIns {
+ insertVar3(bConstraint, val, rightInput, indexMap[rightInput])
+ }
+ cConstraint[indexMap[gate.value.Out]] = big.NewInt(int64(1))
+
+ if gate.value.invert {
+ a = append(a, cConstraint)
+ b = append(b, bConstraint)
+ c = append(c, aConstraint)
+ } else {
+ a = append(a, aConstraint)
+ b = append(b, bConstraint)
+ c = append(c, cConstraint)
+ }
+
+ } else {
+ panic("not a m gate")
+ }
+ }
+ p.R1CS.A = a
+ p.R1CS.B = b
+ p.R1CS.C = c
+ return a, b, c
+}
+
+func insertVar3(arr []*big.Int, val int, input string, index int) {
+ isVal, value := isValue(input)
+ var valueBigInt *big.Int
+ if isVal {
+ valueBigInt = big.NewInt(int64(value))
+ arr[0] = new(big.Int).Add(arr[0], valueBigInt)
+ } else {
+ //if !indexMap[leftInput] {
+ // panic(errors.New("using variable before it's set"))
+ //}
+ valueBigInt = big.NewInt(int64(val))
+ arr[index] = new(big.Int).Add(arr[index], valueBigInt)
+ }
+
+}
+
+func (p *Program) CalculateWitness(input []*big.Int) (witness []*big.Int) {
+
+ if len(p.globalInputs)-1 != len(input) {
+ panic("input do not match the required inputs")
+ }
+
+ witness = r1csqap.ArrayOfBigZeros(len(p.R1CS.A[0]))
+ set := make([]bool, len(witness))
+ witness[0] = big.NewInt(int64(1))
+ set[0] = true
+
+ for i := range input {
+ witness[i+1] = input[i]
+ set[i+1] = true
+ }
+
+ zero := big.NewInt(int64(0))
+
+ for i := 0; i < len(p.R1CS.A); i++ {
+ gatesLeftInputs := p.R1CS.A[i]
+ gatesRightInputs := p.R1CS.B[i]
+ gatesOutputs := p.R1CS.C[i]
+
+ sumLeft := big.NewInt(int64(0))
+ sumRight := big.NewInt(int64(0))
+ sumOut := big.NewInt(int64(0))
+
+ index := -1
+ division := false
+ for j, val := range gatesLeftInputs {
+ if val.Cmp(zero) != 0 {
+ if !set[j] {
+ index = j
+ division = true
+ break
+ }
+ sumLeft.Add(sumLeft, new(big.Int).Mul(val, witness[j]))
+ }
+ }
+ for j, val := range gatesRightInputs {
+ if val.Cmp(zero) != 0 {
+ sumRight.Add(sumRight, new(big.Int).Mul(val, witness[j]))
+ }
+ }
+
+ for j, val := range gatesOutputs {
+ if val.Cmp(zero) != 0 {
+ if !set[j] {
+ if index != -1 {
+ panic("invalid R1CS form")
+ }
+
+ index = j
+ break
+ }
+ sumOut.Add(sumOut, new(big.Int).Mul(val, witness[j]))
+ }
+ }
+
+ if !division {
+ set[index] = true
+ witness[index] = new(big.Int).Mul(sumLeft, sumRight)
+
+ } else {
+ b := sumRight.Int64()
+ c := sumOut.Int64()
+ set[index] = true
+ witness[index] = big.NewInt(c / b)
+ }
+
+ }
+
+ return
+}
diff --git a/circuitcompiler/Programm_test.go b/circuitcompiler/Programm_test.go
new file mode 100644
index 0000000..e25895d
--- /dev/null
+++ b/circuitcompiler/Programm_test.go
@@ -0,0 +1,78 @@
+package circuitcompiler
+
+import (
+ "fmt"
+ "math/big"
+ "strings"
+ "testing"
+)
+
+func TestProgramm_BuildConstraintTree(t *testing.T) {
+ line := "asdf asfd"
+ line = strings.TrimFunc(line, func(i rune) bool { return isWhitespace(i) })
+ fmt.Println(line)
+}
+
+func TestNewProgramm(t *testing.T) {
+
+ flat := `
+ func do(x):
+ e = x * x
+ b = e * e
+ c = b * b
+ d = c * c
+ out = d * 1
+
+ func add(x ,k):
+ z = k * x
+ out = do(x) + mul(x,z)
+
+ func main(a,b):
+ out = do(5) + 4
+
+ func mul(a,b):
+ out = a * b
+ `
+
+ //flat := `
+ //func do(x):
+ // b = x - 2
+ // out = x * b
+ //func main(a,b):
+ // out = do(a) + 4
+ //`
+ parser := NewParser(strings.NewReader(flat))
+ program, err := parser.Parse()
+
+ if err != nil {
+ panic(err)
+ }
+ fmt.Println("\n unreduced")
+ fmt.Println(flat)
+
+ program.BuildConstraintTrees()
+ for k, v := range program.functions {
+ fmt.Println(k)
+ PrintTree(v.root)
+ }
+
+ fmt.Println("\nReduced gates")
+ //PrintTree(froots["mul"])
+ gates := program.ReduceCombinedTree()
+ for _, g := range gates {
+ fmt.Println(g)
+ }
+
+ fmt.Println("generating R1CS")
+ a, b, c := program.GenerateReducedR1CS(gates)
+ fmt.Println(a)
+ fmt.Println(b)
+ fmt.Println(c)
+ a1 := big.NewInt(int64(6))
+ a2 := big.NewInt(int64(5))
+ inputs := []*big.Int{a1, a2}
+ w := program.CalculateWitness(inputs)
+ fmt.Println("witness")
+ fmt.Println(w)
+
+}
diff --git a/circuitcompiler/circuit.go b/circuitcompiler/circuit.go
index 7f4b0af..7353eab 100644
--- a/circuitcompiler/circuit.go
+++ b/circuitcompiler/circuit.go
@@ -2,10 +2,11 @@ package circuitcompiler
import (
"errors"
+ "fmt"
"math/big"
+ "regexp"
"strconv"
-
- "github.com/arnaucube/go-snark/r1csqap"
+ "strings"
)
// Circuit is the data structure of the compiled circuit
@@ -13,174 +14,348 @@ type Circuit struct {
NVars int
NPublic int
NSignals int
- PrivateInputs []string
- PublicInputs []string
+ Inputs []string
Signals []string
+ PublicSignals []string
Witness []*big.Int
- Constraints []Constraint
- R1CS struct {
+ Name string
+ root *gate
+ //after reducing
+ constraintMap map[string]*Constraint
+ //used map[string]bool
+ R1CS struct {
A [][]*big.Int
B [][]*big.Int
C [][]*big.Int
}
}
+type gate struct {
+ index int
+ left *gate
+ right *gate
+ funcInputs []*gate
+ value *Constraint
+ leftIns map[string]int //leftIns and RightIns after addition gates have been reduced. only multiplication gates remain
+ rightIns map[string]int
+}
+
+func (g gate) String() string {
+ return fmt.Sprintf("Gate %v : %v with left %v right %v", g.index, g.value, g.leftIns, g.rightIns)
+}
+
+//type variable struct {
+// val string
+//}
+
// Constraint is the data structure of a flat code operation
type Constraint struct {
// v1 op v2 = out
- Op string
- V1 string
- V2 string
- Out string
- Literal string
+ Op Token
+ V1 string
+ V2 string
+ Out string
+ //fV1 *variable
+ //fV2 *variable
+ //fOut *variable
+ //Literal string
+ Inputs []string // in func declaration case
+ //fInputs []*variable
+ negate bool
+ invert bool
+}
- PrivateInputs []string // in func declaration case
- PublicInputs []string // in func declaration case
+func (c Constraint) String() string {
+ if c.negate || c.invert {
+ return fmt.Sprintf("|%v = %v %v %v| negated: %v, inverted %v", c.Out, c.V1, c.Op, c.V2, c.negate, c.invert)
+ }
+ return fmt.Sprintf("|%v = %v %v %v|", c.Out, c.V1, c.Op, c.V2)
}
-func indexInArray(arr []string, e string) int {
- for i, a := range arr {
- if a == e {
- return i
+func newCircuit(name string) *Circuit {
+ return &Circuit{Name: name, constraintMap: make(map[string]*Constraint)}
+}
+
+func (g *gate) addLeft(c *Constraint) {
+ if g.left != nil {
+ panic("already set left gate")
+ }
+ g.left = &gate{value: c}
+}
+func (g *gate) addRight(c *Constraint) {
+ if g.right != nil {
+ panic("already set left gate")
+ }
+ g.right = &gate{value: c}
+}
+
+func (circ *Circuit) addConstraint(constraint *Constraint) {
+ if _, ex := circ.constraintMap[constraint.Out]; ex {
+ panic("already used FlatConstraint")
+ }
+
+ if constraint.Op == DIVIDE {
+ constraint.Op = MULTIPLY
+ constraint.invert = true
+ } else if constraint.Op == MINUS {
+ constraint.Op = PLUS
+ constraint.negate = true
+ }
+
+ //todo this is dangerous.. if someone would use out as variable name, things would be fucked
+ if constraint.Out == "out" {
+ constraint.Out = composeNewFunction(circ.Name, circ.Inputs)
+ if circ.Name == "main" {
+ //the main functions output must be a multiplication gate
+ //if its not, then we simple create one where outNew = 1 * outOld
+ if constraint.Op&(MINUS|PLUS) != 0 {
+ newOut := &Constraint{Out: constraint.Out, V1: "one", V2: "out2", Op: MULTIPLY}
+ delete(circ.constraintMap, constraint.Out)
+ circ.addConstraint(newOut)
+ constraint.Out = "out2"
+ circ.addConstraint(constraint)
+ }
}
}
- return -1
+
+ addConstantsAndFunctions := func(constraint string) {
+ if b, _ := isValue(constraint); b {
+ circ.constraintMap[constraint] = &Constraint{Op: CONST, Out: constraint}
+ } else if b, _, inputs := isFunction(constraint); b {
+
+ //check if function input is a constant like foo(a,4)
+ for _, in := range inputs {
+ if b, _ := isValue(in); b {
+ circ.constraintMap[in] = &Constraint{Op: CONST, Out: in}
+ }
+ }
+ circ.constraintMap[constraint] = &Constraint{Op: FUNC, Out: constraint, Inputs: inputs}
+ }
+ }
+
+ addConstantsAndFunctions(constraint.V1)
+ addConstantsAndFunctions(constraint.V2)
+
+ circ.constraintMap[constraint.Out] = constraint
}
-func isValue(a string) (bool, int) {
- v, err := strconv.Atoi(a)
- if err != nil {
- return false, 0
+
+func (circ *Circuit) renameInputs(inputs []string) {
+ if len(inputs) != len(circ.Inputs) {
+ panic("given inputs != circuit.Inputs")
}
- return true, v
+ mapping := make(map[string]string)
+ for i := 0; i < len(inputs); i++ {
+ if _, ex := circ.constraintMap[inputs[i]]; ex {
+
+ //this is a tricky part. So we replace former inputs with the new ones, thereby
+ //it might be, that the new input name has already been used for some output inside the function
+ //currently I dont know an elegant way how to handle this renaming issue
+ if circ.constraintMap[inputs[i]].Op != IN {
+ panic(fmt.Sprintf("renaming collsion with %s", inputs[i]))
+ }
+
+ }
+ mapping[circ.Inputs[i]] = inputs[i]
+ }
+ //fmt.Println(mapping)
+ circ.Inputs = inputs
+ permute := func(in string) string {
+ if out, ex := mapping[in]; ex {
+ return out
+ }
+ return in
+ }
+
+ permuteListe := func(in []string) []string {
+ for i := 0; i < len(in); i++ {
+ in[i] = permute(in[i])
+ }
+ return in
+ }
+
+ for _, constraint := range circ.constraintMap {
+
+ if constraint.Op == IN {
+ constraint.Out = permute(constraint.Out)
+ continue
+ }
+
+ if b, n, in := isFunction(constraint.Out); b {
+ constraint.Out = composeNewFunction(n, permuteListe(in))
+ constraint.Inputs = permuteListe(in)
+ }
+ if b, n, in := isFunction(constraint.V1); b {
+ constraint.V1 = composeNewFunction(n, permuteListe(in))
+ constraint.Inputs = permuteListe(in)
+ }
+ if b, n, in := isFunction(constraint.V2); b {
+ constraint.V2 = composeNewFunction(n, permuteListe(in))
+ constraint.Inputs = permuteListe(in)
+ }
+
+ constraint.V1 = permute(constraint.V1)
+ constraint.V2 = permute(constraint.V2)
+
+ }
+ return
}
-func insertVar(arr []*big.Int, signals []string, v string, used map[string]bool) ([]*big.Int, map[string]bool) {
- isVal, value := isValue(v)
- valueBigInt := big.NewInt(int64(value))
- if isVal {
- arr[0] = new(big.Int).Add(arr[0], valueBigInt)
+
+func composeNewFunction(fname string, inputs []string) string {
+ builder := strings.Builder{}
+ builder.WriteString(fname)
+ builder.WriteRune('(')
+ for i := 0; i < len(inputs); i++ {
+ builder.WriteString(inputs[i])
+ if i < len(inputs)-1 {
+ builder.WriteRune(',')
+ }
+ }
+ builder.WriteRune(')')
+ return builder.String()
+}
+
+func max(a, b int) int {
+ if a > b {
+ return a
+ }
+ return b
+}
+
+func TreeDepth(g *gate) int {
+ return printDepth(g, 0)
+}
+
+func printDepth(g *gate, d int) int {
+ d = d + 1
+ if g.left != nil && g.right != nil {
+ return max(printDepth(g.left, d), printDepth(g.right, d))
+ } else if g.left != nil {
+ return printDepth(g.left, d)
+ } else if g.right != nil {
+ return printDepth(g.right, d)
+ }
+ return d
+}
+func CountMultiplicationGates(g *gate) int {
+ if g == nil {
+ return 0
+ }
+ if len(g.rightIns) > 0 || len(g.leftIns) > 0 {
+ return 1 + CountMultiplicationGates(g.left) + CountMultiplicationGates(g.right)
} else {
- if !used[v] {
- panic(errors.New("using variable before it's set"))
+ return CountMultiplicationGates(g.left) + CountMultiplicationGates(g.right)
+ }
+ return 0
+}
+
+//TODO avoid printing multiple times in case of loops
+func PrintTree(g *gate) {
+ printTree(g, 0)
+}
+func printTree(g *gate, d int) {
+ d += 1
+
+ if g.leftIns == nil || g.rightIns == nil {
+ fmt.Printf("Depth: %v - %s \t \t \t \t \n", d, g.value)
+ } else {
+ fmt.Printf("Depth: %v - %s \t \t \t \t with l %v and r %v\n", d, g.value, g.leftIns, g.rightIns)
+ }
+ if g.funcInputs != nil {
+ for _, v := range g.funcInputs {
+ printTree(v, d)
}
- arr[indexInArray(signals, v)] = new(big.Int).Add(arr[indexInArray(signals, v)], big.NewInt(int64(1)))
}
- return arr, used
+
+ if g.left != nil {
+ printTree(g.left, d)
+ }
+ if g.right != nil {
+ printTree(g.right, d)
+ }
}
-func insertVarNeg(arr []*big.Int, signals []string, v string, used map[string]bool) ([]*big.Int, map[string]bool) {
- isVal, value := isValue(v)
- valueBigInt := big.NewInt(int64(value))
- if isVal {
- arr[0] = new(big.Int).Add(arr[0], valueBigInt)
+
+func addToMap(value string, in map[string]int, negate bool) {
+ if negate {
+ in[value] = in[value] - 1
} else {
- if !used[v] {
- panic(errors.New("using variable before it's set"))
+ in[value] = in[value] + 1
+ }
+}
+
+func collectAtomsInSubtree(g *gate, in map[string]int, functionRootMap map[string]*gate, negate bool, invert bool) {
+ if g == nil {
+ return
+ }
+ if g.OperationType()&(MULTIPLY|IN|CONST) != 0 {
+ addToMap(g.value.Out, in, negate)
+ return
+ }
+ if g.OperationType() == FUNC {
+ if b, name, _ := isFunction(g.value.Out); b {
+ collectAtomsInSubtree(functionRootMap[name], in, functionRootMap, negate, invert)
+ } else {
+ panic("function expected")
}
- arr[indexInArray(signals, v)] = new(big.Int).Add(arr[indexInArray(signals, v)], big.NewInt(int64(-1)))
- }
- return arr, used
-}
-
-// GenerateR1CS generates the R1CS polynomials from the Circuit
-func (circ *Circuit) GenerateR1CS() ([][]*big.Int, [][]*big.Int, [][]*big.Int) {
- // from flat code to R1CS
-
- var a [][]*big.Int
- var b [][]*big.Int
- var c [][]*big.Int
-
- used := make(map[string]bool)
- for _, constraint := range circ.Constraints {
- aConstraint := r1csqap.ArrayOfBigZeros(len(circ.Signals))
- bConstraint := r1csqap.ArrayOfBigZeros(len(circ.Signals))
- cConstraint := r1csqap.ArrayOfBigZeros(len(circ.Signals))
-
- // if existInArray(constraint.Out) {
- // if used[constraint.Out] {
- // panic(errors.New("out variable already used: " + constraint.Out))
- // }
- used[constraint.Out] = true
- if constraint.Op == "in" {
- for i := 0; i <= len(circ.PublicInputs); i++ {
- aConstraint[indexInArray(circ.Signals, constraint.Out)] = new(big.Int).Add(aConstraint[indexInArray(circ.Signals, constraint.Out)], big.NewInt(int64(1)))
- aConstraint, used = insertVar(aConstraint, circ.Signals, constraint.Out, used)
- bConstraint[0] = big.NewInt(int64(1))
- }
- continue
- } else if constraint.Op == "+" {
- cConstraint[indexInArray(circ.Signals, constraint.Out)] = big.NewInt(int64(1))
- aConstraint, used = insertVar(aConstraint, circ.Signals, constraint.V1, used)
- aConstraint, used = insertVar(aConstraint, circ.Signals, constraint.V2, used)
- bConstraint[0] = big.NewInt(int64(1))
- } else if constraint.Op == "-" {
- cConstraint[indexInArray(circ.Signals, constraint.Out)] = big.NewInt(int64(1))
- aConstraint, used = insertVarNeg(aConstraint, circ.Signals, constraint.V1, used)
- aConstraint, used = insertVarNeg(aConstraint, circ.Signals, constraint.V2, used)
- bConstraint[0] = big.NewInt(int64(1))
- } else if constraint.Op == "*" {
- cConstraint[indexInArray(circ.Signals, constraint.Out)] = big.NewInt(int64(1))
- aConstraint, used = insertVar(aConstraint, circ.Signals, constraint.V1, used)
- bConstraint, used = insertVar(bConstraint, circ.Signals, constraint.V2, used)
- } else if constraint.Op == "/" {
- cConstraint, used = insertVar(cConstraint, circ.Signals, constraint.V1, used)
- cConstraint[indexInArray(circ.Signals, constraint.Out)] = big.NewInt(int64(1))
- bConstraint, used = insertVar(bConstraint, circ.Signals, constraint.V2, used)
+ }
+
+ collectAtomsInSubtree(g.left, in, functionRootMap, negate, invert)
+ collectAtomsInSubtree(g.right, in, functionRootMap, Xor(negate, g.value.negate), invert)
+}
+
+func Xor(a, b bool) bool {
+ return (a && !b) || (!a && b)
+}
+
+func (g *gate) ExtractValues(in []int) (er error) {
+ if b, v1 := isValue(g.value.V1); b {
+ if b2, v2 := isValue(g.value.V2); b2 {
+ in = append(in, v1, v2)
+ return nil
}
+ }
+ return errors.New(fmt.Sprintf("Gate \"%s\" has no int values", g.value))
+}
- a = append(a, aConstraint)
- b = append(b, bConstraint)
- c = append(c, cConstraint)
+func (g *gate) OperationType() Token {
+ return g.value.Op
+}
+//returns index of e if its in arr
+//return -1 if e not in arr
+func indexInArray(arr []string, e string) int {
+ for i, a := range arr {
+ if a == e {
+ return i
+ }
+ }
+ panic("lul")
+ return -1
+}
+func isValue(a string) (bool, int) {
+ v, err := strconv.Atoi(a)
+ if err != nil {
+ return false, 0
}
- circ.R1CS.A = a
- circ.R1CS.B = b
- circ.R1CS.C = c
- return a, b, c
+ return true, v
}
+func isFunction(a string) (tf bool, name string, inputs []string) {
-func grabVar(signals []string, w []*big.Int, vStr string) *big.Int {
- isVal, v := isValue(vStr)
- vBig := big.NewInt(int64(v))
- if isVal {
- return vBig
- } else {
- return w[indexInArray(signals, vStr)]
+ if !strings.ContainsRune(a, '(') && !strings.ContainsRune(a, ')') {
+ return false, "", nil
}
+ name = strings.Split(a, "(")[0]
+
+ // read string inside ( )
+ rgx := regexp.MustCompile(`\((.*?)\)`)
+ insideParenthesis := rgx.FindStringSubmatch(a)
+ varsString := strings.Replace(insideParenthesis[1], " ", "", -1)
+ inputs = strings.Split(varsString, ",")
+
+ return true, name, inputs
}
type Inputs struct {
Private []*big.Int
- Public []*big.Int
-}
-
-// CalculateWitness calculates the Witness of a Circuit based on the given inputs
-// witness = [ one, output, publicInputs, privateInputs, ...]
-func (circ *Circuit) CalculateWitness(privateInputs []*big.Int, publicInputs []*big.Int) ([]*big.Int, error) {
- if len(privateInputs) != len(circ.PrivateInputs) {
- return []*big.Int{}, errors.New("given privateInputs != circuit.PublicInputs")
- }
- if len(publicInputs) != len(circ.PublicInputs) {
- return []*big.Int{}, errors.New("given publicInputs != circuit.PublicInputs")
- }
- w := r1csqap.ArrayOfBigZeros(len(circ.Signals))
- w[0] = big.NewInt(int64(1))
- for i, input := range publicInputs {
- w[i+1] = input
- }
- for i, input := range privateInputs {
- w[i+len(publicInputs)+1] = input
- }
- for _, constraint := range circ.Constraints {
- if constraint.Op == "in" {
- } else if constraint.Op == "+" {
- w[indexInArray(circ.Signals, constraint.Out)] = new(big.Int).Add(grabVar(circ.Signals, w, constraint.V1), grabVar(circ.Signals, w, constraint.V2))
- } else if constraint.Op == "-" {
- w[indexInArray(circ.Signals, constraint.Out)] = new(big.Int).Sub(grabVar(circ.Signals, w, constraint.V1), grabVar(circ.Signals, w, constraint.V2))
- } else if constraint.Op == "*" {
- w[indexInArray(circ.Signals, constraint.Out)] = new(big.Int).Mul(grabVar(circ.Signals, w, constraint.V1), grabVar(circ.Signals, w, constraint.V2))
- } else if constraint.Op == "/" {
- w[indexInArray(circ.Signals, constraint.Out)] = new(big.Int).Div(grabVar(circ.Signals, w, constraint.V1), grabVar(circ.Signals, w, constraint.V2))
- }
- }
- return w, nil
+ Publics []*big.Int
}
diff --git a/circuitcompiler/circuit_test.go b/circuitcompiler/circuit_test.go
index 485406b..c0fe98f 100644
--- a/circuitcompiler/circuit_test.go
+++ b/circuitcompiler/circuit_test.go
@@ -1,88 +1,128 @@
package circuitcompiler
import (
- "math/big"
- "strings"
+ //"fmt"
+ ////"math/big"
+ //"strings"
"testing"
"github.com/stretchr/testify/assert"
)
+func TestXor(t *testing.T) {
+ assert.Equal(t, false, Xor(true, true))
+ assert.Equal(t, true, Xor(true, false))
+ assert.Equal(t, true, Xor(false, true))
+ assert.Equal(t, false, Xor(false, false))
+
+}
+
func TestCircuitParser(t *testing.T) {
- // y = x^3 + x + 5
- flat := `
- func test(private s0, public s1):
- s2 = s0 * s0
- s3 = s2 * s0
- s4 = s3 + s0
- s5 = s4 + 5
- equals(s1, s5)
- out = 1 * 1
- `
- parser := NewParser(strings.NewReader(flat))
- 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])
+ //flat := `
+ //func main(a,b):
+ // c = a / b
+ // d = c * b
+ // e = d - c
+ // f = c * 55
+ // out = f / e
+ //`
+ //flat := `
+ //func test(a,b):
+ // d = a / b
+ // c = a + d
+ // f = a * 55
+ // g = a / d
+ // h = g + f
+ // i = c + h
+ // out = i / c
+ //`
+ //parser := NewParser(strings.NewReader(flat))
+ //programm, err := parser.Parse()
+ //circuit := programm.getMainCircut()
+ //assert.Nil(t, err)
+ //fmt.Println("\n unreduced")
+ //fmt.Println(flat)
- assert.Equal(t, []string{"one", "s1", "s0", "s2", "s3", "s4", "s5", "out"}, circuit.Signals)
+ //fmt.Println("generating R1CS from flat code")
+ //a, b, c := circuit.GenerateR1CS()
+ //fmt.Println(a)
+ //fmt.Println(b)
+ //fmt.Println(c)
+ //
+ //a1 := big.NewInt(int64(6))
+ //a2 := big.NewInt(int64(5))
+ //inputs := []*big.Int{a1, a2}
+ //// Calculate Witness
+ //w, err := circuit.CalculateWitness(inputs)
+ //assert.Nil(t, err)
+ //fmt.Println("w", w)
+ //fmt.Printf("inputs %s", circuit.Inputs)
+ //fmt.Printf("signals %s", 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, b0, b1, 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, b1, 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},
- []*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},
- }
+ //
+ //fmt.Println("Reduced Tree Parsing")
+ //r := circuit.BuildConstraintTree()
+ //constraintReduced := ReduceTree(r)
+ //fmt.Printf("depth %v, mGates %v \n", printDepth(r, 0), CountMultiplicationGates(r))
+ //printTree(r, 0)
+ //
+ //a,b,c,w = circuit.GenerateReducedR1CSandWitness(inputs,constraintReduced)
+ //fmt.Println("\ngenerating R1CS from reduced flat code")
+ //fmt.Println("\nR1CS:")
+ //fmt.Println("a:", a)
+ //fmt.Println("b:", b)
+ //fmt.Println("c:", c)
+ //fmt.Println("w", w)
- assert.Equal(t, aExpected, a)
- assert.Equal(t, bExpected, b)
- assert.Equal(t, cExpected, c)
+ //// R1CS to QAP
+ //alphas, betas, gammas, zxQAP := fields.R1CSToQAP(a, b, c)
+ //fmt.Println("qap")
+ //fmt.Println("alphas", len(alphas))
+ //fmt.Println("alphas", alphas[0])
+ //fmt.Println("betas", len(betas))
+ //fmt.Println("gammas", len(gammas))
+ //fmt.Println("zx length", len(zxQAP))
+ //circuit.reduceAdditionGates()
+ //
+ //fmt.Println(circuit)
+ //fmt.Println("generating R1CS from flat code")
+ //a, b, c = circuit.GenerateR1CS()
+ //
+ //fmt.Println(a)
+ //fmt.Println(b)
+ //fmt.Println(c)
+ //
+ //// Calculate Witness
+ //w, err = circuit.CalculateWitness(inputs)
+ //assert.Nil(t, err)
+ //fmt.Println("w", w)
- 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)
+ //// 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},
+ // []*big.Int{b0, b0, b0, b1, b0, b0},
+ // []*big.Int{b0, b0, b1, b0, b1, b0},
+ // []*big.Int{b5, b0, b0, b0, b0, b1},
+ //}
+ //bExpected := [][]*big.Int{
+ // []*big.Int{b0, b0, b1, b0, b0, b0},
+ // []*big.Int{b0, b0, b1, b0, b0, b0},
+ // []*big.Int{b1, b0, b0, b0, b0, b0},
+ // []*big.Int{b1, b0, b0, b0, b0, b0},
+ //}
+ //cExpected := [][]*big.Int{
+ // []*big.Int{b0, b0, b0, b1, b0, b0},
+ // []*big.Int{b0, b0, b0, b0, b1, b0},
+ // []*big.Int{b0, b0, b0, b0, b0, b1},
+ // []*big.Int{b0, b1, b0, b0, b0, b0},
+ //}
- // circuitJson, _ := json.Marshal(circuit)
- // fmt.Println("circuit:", string(circuitJson))
+ //assert.Equal(t, aExpected, a)
+ //assert.Equal(t, bExpected, b)
+ //assert.Equal(t, cExpected, c)
- assert.Equal(t, circuit.NPublic, 1)
- assert.Equal(t, len(circuit.PublicInputs), 1)
- assert.Equal(t, len(circuit.PrivateInputs), 1)
}
diff --git a/circuitcompiler/lexer.go b/circuitcompiler/lexer.go
index 92bc45c..94abd92 100644
--- a/circuitcompiler/lexer.go
+++ b/circuitcompiler/lexer.go
@@ -10,25 +10,50 @@ type OperatorSymbol int
type Token int
const (
- ILLEGAL Token = iota
+ ILLEGAL Token = 1 << iota
WS
EOF
-
+ FUNC
IDENT // val
-
- VAR // var
- CONST // const value
-
+ IN
+ VAR // var
+ CONST // const value
EQ // =
PLUS // +
MINUS // -
MULTIPLY // *
DIVIDE // /
EXP // ^
-
OUT
)
+func (ch Token) String() string {
+ switch ch {
+ case EQ:
+ return "="
+ case PLUS:
+ return "+"
+ case MINUS:
+ return "-"
+ case MULTIPLY:
+ return "*"
+ case DIVIDE:
+ return "/"
+ case EXP:
+ return "^"
+ case FUNC:
+ return "func"
+ case IN:
+ return "In"
+ case CONST:
+ return "Const"
+ default:
+ return "unknown Token"
+
+ }
+
+}
+
var eof = rune(0)
func isWhitespace(ch rune) bool {
@@ -96,6 +121,8 @@ func (s *Scanner) scan() (tok Token, lit string) {
return DIVIDE, "/"
case '^':
return EXP, "^"
+ //case '(':
+ // return EXP, "func"
}
return ILLEGAL, string(ch)
@@ -121,10 +148,20 @@ func (s *Scanner) scanWhitespace() (token Token, lit string) {
func (s *Scanner) scanIndent() (tok Token, lit string) {
var buf bytes.Buffer
buf.WriteRune(s.read())
-
+ tok = IDENT
for {
if ch := s.read(); ch == eof {
break
+ } else if ch == '(' {
+ tok = FUNC
+ _, _ = buf.WriteRune(ch)
+ } else if ch == ',' && tok == FUNC {
+ _, _ = buf.WriteRune(ch)
+ } else if isWhitespace(ch) && tok == FUNC {
+ continue
+ } else if ch == ')' && tok == FUNC {
+ _, _ = buf.WriteRune(ch)
+ break
} else if !isLetter(ch) && !isDigit(ch) {
s.unread()
break
@@ -132,6 +169,7 @@ func (s *Scanner) scanIndent() (tok Token, lit string) {
_, _ = buf.WriteRune(ch)
}
}
+
switch buf.String() {
case "var":
return VAR, buf.String()
diff --git a/circuitcompiler/parser.go b/circuitcompiler/parser.go
index 70f074b..3364616 100644
--- a/circuitcompiler/parser.go
+++ b/circuitcompiler/parser.go
@@ -2,9 +2,7 @@ package circuitcompiler
import (
"errors"
- "fmt"
"io"
- "os"
"regexp"
"strings"
)
@@ -59,12 +57,18 @@ func (p *Parser) parseLine() (*Constraint, error) {
*/
c := &Constraint{}
tok, lit := p.scanIgnoreWhitespace()
- c.Out = lit
- c.Literal += lit
-
- if c.Literal == "func" {
+ switch lit {
+ case "func":
+ c.Op = FUNC
// format: `func name(in):`
+ //todo this is all a bit hacky and unsafe
line, err := p.s.r.ReadString(':')
+ line = strings.Replace(line, " ", "", -1)
+ line = strings.Replace(line, ":", "", -1)
+ //set function name
+ //c.Literal = strings.Split(line, "(")[0]
+ c.Out = line
+
if err != nil {
return c, err
}
@@ -72,59 +76,45 @@ func (p *Parser) parseLine() (*Constraint, error) {
rgx := regexp.MustCompile(`\((.*?)\)`)
insideParenthesis := rgx.FindStringSubmatch(line)
varsString := strings.Replace(insideParenthesis[1], " ", "", -1)
- allInputs := strings.Split(varsString, ",")
-
- // from allInputs, get the private and the public separated
- for _, in := range allInputs {
- if strings.Contains(in, "private") {
- input := strings.Replace(in, "private", "", -1)
- c.PrivateInputs = append(c.PrivateInputs, input)
- } else if strings.Contains(in, "public") {
- input := strings.Replace(in, "public", "", -1)
- c.PublicInputs = append(c.PublicInputs, input)
- } else {
- // TODO give more info about the circuit code error
- fmt.Println("error on declaration of public and private inputs")
- os.Exit(0)
- }
- }
- return c, nil
- }
- if c.Literal == "equals" {
- // format: `equals(a, b)`
- line, err := p.s.r.ReadString(')')
- if err != nil {
- return c, err
- }
- // read string inside ( )
- rgx := regexp.MustCompile(`\((.*?)\)`)
- insideParenthesis := rgx.FindStringSubmatch(line)
- varsString := strings.Replace(insideParenthesis[1], " ", "", -1)
- params := strings.Split(varsString, ",")
- c.V1 = params[0]
- c.V2 = params[1]
+ c.Inputs = strings.Split(varsString, ",")
return c, nil
+ case "var":
+ //var a = 234
+ //c.Literal += lit
+ _, lit = p.scanIgnoreWhitespace()
+ c.Out = lit
+ //c.Literal += lit
+ _, lit = p.scanIgnoreWhitespace() // skip =
+ //c.Literal += lit
+ // v1
+ _, lit = p.scanIgnoreWhitespace()
+ c.V1 = lit
+ //c.Literal += lit
+ break
+ case "#":
+ return nil, errors.New("comment parseline")
+ default:
+ c.Out = lit
+ //c.Literal += lit
+ _, lit = p.scanIgnoreWhitespace() // skip =
+ //c.Literal += lit
+
+ // v1
+ tok, lit = p.scanIgnoreWhitespace()
+ c.V1 = lit
+ //c.Literal += lit
+
+ // operator
+ tok, lit = p.scanIgnoreWhitespace()
+
+ c.Op = tok
+ //c.Literal += lit
+ // v2
+ _, lit = p.scanIgnoreWhitespace()
+ c.V2 = lit
+ //c.Literal += lit
}
- // if c.Literal == "out" {
- // // TODO
- // return c, nil
- // }
-
- _, lit = p.scanIgnoreWhitespace() // skip =
- c.Literal += lit
-
- // v1
- _, lit = p.scanIgnoreWhitespace()
- c.V1 = lit
- c.Literal += lit
- // operator
- _, lit = p.scanIgnoreWhitespace()
- c.Op = lit
- c.Literal += lit
- // v2
- _, lit = p.scanIgnoreWhitespace()
- c.V2 = lit
- c.Literal += lit
+
if tok == EOF {
return nil, errors.New("eof in parseline")
}
@@ -151,92 +141,26 @@ func addToArrayIfNotExist(arr []string, elem string) []string {
}
// Parse parses the lines and returns the compiled Circuit
-func (p *Parser) Parse() (*Circuit, error) {
- circuit := &Circuit{}
- circuit.Signals = append(circuit.Signals, "one")
- nInputs := 0
+func (p *Parser) Parse() (programm *Program, err error) {
+ programm = NewProgramm()
+
+ var circuit *Circuit
+
for {
constraint, err := p.parseLine()
if err != nil {
break
}
- if constraint.Literal == "func" {
- // one constraint for each input
- for _, in := range constraint.PublicInputs {
- newConstr := &Constraint{
- Op: "in",
- Out: in,
- }
- circuit.Constraints = append(circuit.Constraints, *newConstr)
- nInputs++
- circuit.Signals = addToArrayIfNotExist(circuit.Signals, in)
- circuit.NPublic++
- }
- for _, in := range constraint.PrivateInputs {
- newConstr := &Constraint{
- Op: "in",
- Out: in,
- }
- circuit.Constraints = append(circuit.Constraints, *newConstr)
- nInputs++
- circuit.Signals = addToArrayIfNotExist(circuit.Signals, in)
- }
- circuit.PublicInputs = constraint.PublicInputs
- circuit.PrivateInputs = constraint.PrivateInputs
- continue
+ if constraint.Op == FUNC {
+ circuit = programm.addFunction(constraint)
+ } else {
+ circuit.addConstraint(constraint)
}
- if constraint.Literal == "equals" {
- constr1 := &Constraint{
- Op: "*",
- V1: constraint.V2,
- V2: "1",
- Out: constraint.V1,
- Literal: "equals(" + constraint.V1 + ", " + constraint.V2 + "): " + constraint.V1 + "==" + constraint.V2 + " * 1",
- }
- circuit.Constraints = append(circuit.Constraints, *constr1)
- constr2 := &Constraint{
- Op: "*",
- V1: constraint.V1,
- V2: "1",
- Out: constraint.V2,
- Literal: "equals(" + constraint.V1 + ", " + constraint.V2 + "): " + constraint.V2 + "==" + constraint.V1 + " * 1",
- }
- circuit.Constraints = append(circuit.Constraints, *constr2)
- continue
- }
- circuit.Constraints = append(circuit.Constraints, *constraint)
- isVal, _ := isValue(constraint.V1)
- if !isVal {
- circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V1)
- }
- isVal, _ = isValue(constraint.V2)
- if !isVal {
- circuit.Signals = addToArrayIfNotExist(circuit.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)
- // }
}
- circuit.NVars = len(circuit.Signals)
- circuit.NSignals = len(circuit.Signals)
- return circuit, nil
+ //TODO
+ //circuit.NVars = len(circuit.Signals)
+ //circuit.NSignals = len(circuit.Signals)
+ return programm, nil
}
func copyArray(in []string) []string { // tmp
var out []string
diff --git a/cli/main.go b/cli/main.go
index 0777b46..62aa1d7 100644
--- a/cli/main.go
+++ b/cli/main.go
@@ -11,9 +11,9 @@ 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/mottla/go-snark"
+ "github.com/mottla/go-snark/circuitcompiler"
+ "github.com/mottla/go-snark/r1csqap"
"github.com/urfave/cli"
)
diff --git a/r1csqap/r1csqap.go b/r1csqap/r1csqap.go
index 7429b74..824a247 100644
--- a/r1csqap/r1csqap.go
+++ b/r1csqap/r1csqap.go
@@ -4,7 +4,7 @@ import (
"bytes"
"math/big"
- "github.com/arnaucube/go-snark/fields"
+ "github.com/mottla/go-snark/fields"
)
// Transpose transposes the *big.Int matrix
diff --git a/r1csqap/r1csqap_test.go b/r1csqap/r1csqap_test.go
index 54dba62..184bcca 100644
--- a/r1csqap/r1csqap_test.go
+++ b/r1csqap/r1csqap_test.go
@@ -5,7 +5,7 @@ import (
"math/big"
"testing"
- "github.com/arnaucube/go-snark/fields"
+ "github.com/mottla/go-snark/fields"
"github.com/stretchr/testify/assert"
)
diff --git a/snark.go b/snark.go
index 642fc54..333dc02 100644
--- a/snark.go
+++ b/snark.go
@@ -5,10 +5,10 @@ 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/mottla/go-snark/bn128"
+ "github.com/mottla/go-snark/circuitcompiler"
+ "github.com/mottla/go-snark/fields"
+ "github.com/mottla/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
diff --git a/snark_test.go b/snark_test.go
index a1c070c..32f9d55 100644
--- a/snark_test.go
+++ b/snark_test.go
@@ -1,185 +1,77 @@
package snark
import (
- "bytes"
"fmt"
+ "github.com/mottla/go-snark/circuitcompiler"
+ "github.com/mottla/go-snark/r1csqap"
+ "github.com/stretchr/testify/assert"
"math/big"
"strings"
"testing"
- "time"
-
- "github.com/arnaucube/go-snark/circuitcompiler"
- "github.com/arnaucube/go-snark/r1csqap"
- "github.com/stretchr/testify/assert"
)
-func TestZkFromFlatCircuitCode(t *testing.T) {
- // compile circuit and get the R1CS
-
- // circuit function
- // y = x^3 + x + 5
- flatCode := `
- 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("\nflat code of the circuit:")
- fmt.Println(flatCode)
-
- // parse the code
- parser := circuitcompiler.NewParser(strings.NewReader(flatCode))
- circuit, err := parser.Parse()
- assert.Nil(t, err)
- // fmt.Println("\ncircuit data:", circuit)
- // circuitJson, _ := json.Marshal(circuit)
- // fmt.Println("circuit:", string(circuitJson))
-
- 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)
-
- // flat code to R1CS
- fmt.Println("\ngenerating R1CS from flat 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, zxQAP := 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.Equal(t, 7, len(zxQAP))
- 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))
-
- hxQAP := Utils.PF.DivisorPolynomial(px, zxQAP)
- assert.Equal(t, 7, len(hxQAP))
-
- // hx==px/zx so px==hx*zx
- assert.Equal(t, px, Utils.PF.Mul(hxQAP, zxQAP))
-
- // p(x) = a(x) * b(x) - c(x) == h(x) * z(x)
- abc := Utils.PF.Sub(Utils.PF.Mul(ax, bx), cx)
- assert.Equal(t, abc, px)
- hzQAP := Utils.PF.Mul(hxQAP, zxQAP)
- assert.Equal(t, abc, hzQAP)
-
- div, rem := Utils.PF.Div(px, zxQAP)
- assert.Equal(t, hxQAP, div)
- assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(6))
-
- // calculate trusted setup
- setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas)
- assert.Nil(t, err)
- fmt.Println("\nt:", setup.Toxic.T)
-
- // zx and setup.Pk.Z should be the same (currently not, the correct one is the calculation used inside GenerateTrustedSetup function), the calculation is repeated. TODO avoid repeating calculation
- assert.Equal(t, zxQAP, setup.Pk.Z)
-
- hx := Utils.PF.DivisorPolynomial(px, setup.Pk.Z)
- assert.Equal(t, hx, hxQAP)
- // assert.Equal(t, hxQAP, hx)
- div, rem = Utils.PF.Div(px, setup.Pk.Z)
- assert.Equal(t, hx, div)
- assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(6))
-
- assert.Equal(t, px, Utils.PF.Mul(hxQAP, zxQAP))
- // 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)
- assert.Equal(t, len(hxQAP), len(px)-len(zxQAP)+1)
-
- proof, err := GenerateProofs(*circuit, setup, w, px)
- assert.Nil(t, err)
-
- // fmt.Println("\n proofs:")
- // fmt.Println(proof)
+func TestNewProgramm(t *testing.T) {
- // 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))
+ flat := `
- // 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))
-}
+ func add(x ,k):
+ z = k * x
+ out = x + mul(x,z)
+
+ func main(a,b):
+ out = add(a,b) * a
-func TestZkMultiplication(t *testing.T) {
- flatCode := `
- func test(private a, private b, public c):
- d = a * b
- equals(c, d)
- out = 1 * 1
+ func mul(a,b):
+ out = a * b
`
- fmt.Println("flat code", flatCode)
-
- // parse the code
- parser := circuitcompiler.NewParser(strings.NewReader(flatCode))
- circuit, err := parser.Parse()
- assert.Nil(t, err)
-
- b3 := big.NewInt(int64(3))
- b4 := big.NewInt(int64(4))
- privateInputs := []*big.Int{b3, b4}
- b12 := big.NewInt(int64(12))
- publicSignals := []*big.Int{b12}
- // wittness
- w, err := circuit.CalculateWitness(privateInputs, publicSignals)
- assert.Nil(t, err)
-
- // flat code to R1CS
- fmt.Println("\ngenerating R1CS from flat code")
- a, b, c := circuit.GenerateR1CS()
- fmt.Println("\nR1CS:")
- fmt.Println("a:", a)
- fmt.Println("b:", b)
- fmt.Println("c:", c)
+ parser := circuitcompiler.NewParser(strings.NewReader(flat))
+ program, err := parser.Parse()
+
+ if err != nil {
+ panic(err)
+ }
+ fmt.Println("\n unreduced")
+ fmt.Println(flat)
+
+ program.BuildConstraintTrees()
+ program.PrintConstraintTrees()
+ fmt.Println("\nReduced gates")
+ //PrintTree(froots["mul"])
+ gates := program.ReduceCombinedTree()
+ for _, g := range gates {
+ fmt.Println(g)
+ }
+
+ fmt.Println("generating R1CS")
+ a, b, c := program.GenerateReducedR1CS(gates)
+ fmt.Println(a)
+ fmt.Println(b)
+ fmt.Println(c)
+ a1 := big.NewInt(int64(6))
+ a2 := big.NewInt(int64(5))
+ inputs := []*big.Int{a1, a2}
+ w := program.CalculateWitness(inputs)
+ fmt.Println("witness")
+ fmt.Println(w)
// R1CS to QAP
- // TODO zxQAP is not used and is an old impl. TODO remove
alphas, betas, gammas, zxQAP := Utils.PF.R1CSToQAP(a, b, c)
- assert.Equal(t, 6, len(alphas))
- assert.Equal(t, 6, len(betas))
- assert.Equal(t, 6, len(betas))
- assert.Equal(t, 5, len(zxQAP))
- assert.True(t, !bytes.Equal(alphas[1][1].Bytes(), big.NewInt(int64(0)).Bytes()))
+ fmt.Println("qap")
+ fmt.Println("alphas", len(alphas))
+ fmt.Println("alphas", alphas)
+ fmt.Println("betas", len(betas))
+ fmt.Println("gammas", len(gammas))
+ fmt.Println("zx length", len(zxQAP))
ax, bx, cx, px := Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
- assert.Equal(t, 4, len(ax))
- assert.Equal(t, 4, len(bx))
- assert.Equal(t, 4, len(cx))
- assert.Equal(t, 7, len(px))
+ fmt.Println("ax length", len(ax))
+ fmt.Println("bx length", len(bx))
+ fmt.Println("cx length", len(cx))
+ fmt.Println("px length", len(px))
hxQAP := Utils.PF.DivisorPolynomial(px, zxQAP)
- assert.Equal(t, 3, len(hxQAP))
+ fmt.Println("hx length", len(hxQAP))
// hx==px/zx so px==hx*zx
assert.Equal(t, px, Utils.PF.Mul(hxQAP, zxQAP))
@@ -195,135 +87,39 @@ func TestZkMultiplication(t *testing.T) {
assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(4))
// calculate trusted setup
- setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas)
- assert.Nil(t, err)
- // fmt.Println("\nt:", setup.Toxic.T)
-
- // zx and setup.Pk.Z should be the same (currently not, the correct one is the calculation used inside GenerateTrustedSetup function), the calculation is repeated. TODO avoid repeating calculation
- assert.Equal(t, zxQAP, setup.Pk.Z)
-
- hx := Utils.PF.DivisorPolynomial(px, setup.Pk.Z)
- assert.Equal(t, 3, len(hx))
- assert.Equal(t, hx, hxQAP)
-
- div, rem = Utils.PF.Div(px, setup.Pk.Z)
- assert.Equal(t, hx, div)
- assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(4))
-
- assert.Equal(t, px, Utils.PF.Mul(hxQAP, zxQAP))
- // 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)
- assert.Equal(t, len(hxQAP), len(px)-len(zxQAP)+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("\n", circuit.Signals)
- fmt.Println("witness", w)
- b12Verif := big.NewInt(int64(12))
- publicSignalsVerif := []*big.Int{b12Verif}
- 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(11))
- wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic}
- assert.True(t, !VerifyProof(*circuit, setup, proof, wrongPublicSignalsVerif, true))
-}
-
-func TestMinimalFlow(t *testing.T) {
- // circuit function
- // y = x^3 + x + 5
- flatCode := `
- 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("\nflat code of the circuit:")
- fmt.Println(flatCode)
-
- // parse the code
- parser := circuitcompiler.NewParser(strings.NewReader(flatCode))
- 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)
-
- // flat code to R1CS
- fmt.Println("\ngenerating R1CS from flat 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))
-
- // calculate trusted setup
- 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, true))
+ //setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas)
+ //assert.Nil(t, err)
+ //fmt.Println("\nt:", setup.Toxic.T)
+ //
+ //// zx and setup.Pk.Z should be the same (currently not, the correct one is the calculation used inside GenerateTrustedSetup function), the calculation is repeated. TODO avoid repeating calculation
+ //// assert.Equal(t, zxQAP, setup.Pk.Z)
+ //
+ //fmt.Println("hx pk.z", hxQAP)
+ //hx := Utils.PF.DivisorPolynomial(px, setup.Pk.Z)
+ //fmt.Println("hx pk.z", hx)
+ //// assert.Equal(t, hxQAP, hx)
+ //assert.Equal(t, px, Utils.PF.Mul(hxQAP, zxQAP))
+ //assert.Equal(t, px, Utils.PF.Mul(hx, setup.Pk.Z))
+ //
+ //assert.Equal(t, len(hx), len(px)-len(setup.Pk.Z)+1)
+ //assert.Equal(t, len(hxQAP), len(px)-len(zxQAP)+1)
+ //// fmt.Println("pk.Z", len(setup.Pk.Z))
+ //// fmt.Println("zxQAP", len(zxQAP))
+ //
+ //// piA = g1 * A(t), piB = g2 * B(t), piC = g1 * C(t), piH = g1 * H(t)
+ //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("\nwitness", w)
+ //// b1 := big.NewInt(int64(1))
+ //b35 := big.NewInt(int64(35))
+ //// publicSignals := []*big.Int{b1, b35}
+ //publicSignals := []*big.Int{b35}
+ //before := time.Now()
+ //assert.True(t, VerifyProof(*circuit, setup, proof, publicSignals, true))
+ //fmt.Println("verify proof time elapsed:", time.Since(before))
}