diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index a0d95a3..35c65d2 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,6 +5,7 @@
+
@@ -17,8 +18,8 @@
-
-
+
+
@@ -35,7 +36,7 @@
-
+
@@ -50,11 +51,11 @@
-
+
-
-
+
+
@@ -62,11 +63,23 @@
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -74,8 +87,8 @@
-
-
+
+
@@ -145,14 +158,14 @@
-
-
-
+
+
+
@@ -167,7 +180,6 @@
-
@@ -184,65 +196,11 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -343,34 +301,34 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -385,14 +343,13 @@
-
-
+
-
+
@@ -442,7 +399,9 @@
-
+
+
+
@@ -494,14 +453,63 @@
file://$PROJECT_DIR$/circuitcompiler/Programm.go
- 244
+ 204
file://$PROJECT_DIR$/circuitcompiler/Programm.go
- 111
+ 421
+
+
+
+ file://$PROJECT_DIR$/circuitcompiler/Programm.go
+ 425
+
+
+
+ file://$PROJECT_DIR$/circuitcompiler/Programm.go
+ 406
+
+
+
+ file://$PROJECT_DIR$/circuitcompiler/Programm.go
+ 410
+
+
+
+ file://$PROJECT_DIR$/circuitcompiler/Programm.go
+ 275
+
+
+
+ file://$PROJECT_DIR$/circuitcompiler/Programm.go
+ 276
+
+
+
+
+ file://$PROJECT_DIR$/circuitcompiler/Programm.go
+ 299
+
+
+
+
+ file://$PROJECT_DIR$/circuitcompiler/Programm.go
+ 292
+
+
+
+
+ file://$PROJECT_DIR$/circuitcompiler/Programm.go
+ 370
+
+
+
+
+ file://$PROJECT_DIR$/circuitcompiler/Programm.go
+ 380
-
+
@@ -644,16 +652,6 @@
-
-
-
-
-
-
-
-
-
-
@@ -734,10 +732,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
@@ -761,13 +776,6 @@
-
-
-
-
-
-
-
@@ -777,25 +785,25 @@
-
-
+
+
-
+
-
-
-
-
-
+
+
-
+
-
-
+
+
+
+
+
diff --git a/circuitcompiler/Programm.go b/circuitcompiler/Programm.go
index 3941a94..2fa8c41 100644
--- a/circuitcompiler/Programm.go
+++ b/circuitcompiler/Programm.go
@@ -6,6 +6,7 @@ import (
"github.com/mottla/go-snark/fields"
"github.com/mottla/go-snark/r1csqap"
"math/big"
+ "sync"
)
type utils struct {
@@ -15,11 +16,11 @@ type utils struct {
}
type Program struct {
- functions map[string]*Circuit
- globalInputs []Constraint
- arithmeticEnvironment utils //find a better name
- extendedFunctionRenamer func(context *Circuit, c Constraint) (newContext *Circuit)
- R1CS struct {
+ functions map[string]*Circuit
+ globalInputs []Constraint
+ arithmeticEnvironment utils //find a better name
+
+ R1CS struct {
A [][]*big.Int
B [][]*big.Int
C [][]*big.Int
@@ -35,16 +36,26 @@ func (p *Program) PrintContraintTrees() {
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 := circuit.gateMap[fName]
- functionRootMap[fName] = root
- circuit.root = root
- circuit.buildTree(root)
+ mainRoot := p.getMainCircuit().root
+
+ if mainRoot.value.Op&(MINUS|PLUS) != 0 {
+ newOut := Constraint{Out: "out", V1: "1", V2: "out2", Op: MULTIPLY}
+ p.getMainCircuit().addConstraint(&newOut)
+ mainRoot.value.Out = "main@out2"
+ p.getMainCircuit().gateMap[mainRoot.value.Out] = mainRoot
}
+ var wg = sync.WaitGroup{}
+
+ for _, circuit := range p.functions {
+ wg.Add(1)
+ func() {
+ circuit.buildTree(circuit.root)
+ wg.Done()
+ }()
+
+ }
+ wg.Wait()
return
}
@@ -61,8 +72,6 @@ func (c *Circuit) buildTree(g *gate) {
//g.funcInputs = []*gate{}
for _, in := range g.value.Inputs {
if gate, ex := c.gateMap[in]; ex {
- //sadf
-
g.funcInputs = append(g.funcInputs, gate)
//note that we do repeated work here. the argument
c.buildTree(gate)
@@ -90,56 +99,11 @@ func (c *Circuit) buildTree(g *gate) {
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
- }
-
- p.extendedFunctionRenamer = func(context *Circuit, c Constraint) (nextContext *Circuit) {
- if c.Op != FUNC {
- panic("not a function")
- }
- if _, ex := context.gateMap[c.Out]; !ex {
- panic("constraint mus be within the context circuit")
- }
-
- if b, name, in := isFunction(c.Out); b {
- if newContext, v := p.functions[name]; v {
- //fmt.Println("unrenamed thing")
- //PrintTree(k.root)
- for i, argument := range in {
- if gate, ex := context.gateMap[argument]; ex {
- oldGate := newContext.gateMap[newContext.Inputs[i]]
- //we take the old gate which was nothing but a input
- //and link this input to its constituents comming from the calling context.
- //i think this is pretty neat
- oldGate.value = gate.value
- oldGate.right = gate.right
- oldGate.left = gate.left
-
- } else {
- panic("not expected")
- }
- }
-
- newContext.renameInputs(in)
-
- //fmt.Println("renamed thing")
- //PrintTree(k.root)
- return newContext
- }
- }
- panic("not a function dude")
- return nil
- }
- //traverseCombinedMultiplicationGates(p.getMainCircut().root, mGatesUsed, &orderedmGates, functionRootMap, functionRenamer, false, false)
-
- //markMgates(p.getMainCircut().root, mGatesUsed, &orderedmGates, functionRenamer, false, false)
- p.markMgates2(p.getMainCircut(), p.getMainCircut().root, mGatesUsed, &orderedmGates, false, false)
+ p.r1CSRecursiveBuild(p.getMainCircuit(), p.getMainCircuit().root, mGatesUsed, &orderedmGates, false, false)
return orderedmGates
}
-func (p *Program) markMgates2(contextCircut *Circuit, root *gate, mGatesUsed map[string]bool, orderedmGates *[]gate, negate bool, inverse bool) (isConstant bool) {
+func (p *Program) r1CSRecursiveBuild(currentCircuit *Circuit, root *gate, mGatesUsed map[string]bool, orderedmGates *[]gate, negate bool, inverse bool) (isConstant bool) {
if root.OperationType() == IN {
return false
@@ -149,27 +113,31 @@ func (p *Program) markMgates2(contextCircut *Circuit, root *gate, mGatesUsed map
return true
}
+ if _, alreadyComputed := mGatesUsed[root.value.Out]; alreadyComputed {
+ return false
+ }
+
if root.OperationType() == FUNC {
- nextContext := p.extendedFunctionRenamer(contextCircut, root.value)
- isConstant = p.markMgates2(nextContext, nextContext.root, mGatesUsed, orderedmGates, negate, inverse)
- } else {
- if _, alreadyComputed := mGatesUsed[root.value.V1]; !alreadyComputed {
- isConstant = p.markMgates2(contextCircut, root.left, mGatesUsed, orderedmGates, negate, inverse)
- }
+ nextContext := p.extendedFunctionRenamer(currentCircuit, root.value)
+ isConstant = p.r1CSRecursiveBuild(nextContext, nextContext.root, mGatesUsed, orderedmGates, negate, inverse)
+ return isConstant
+ }
- if _, alreadyComputed := mGatesUsed[root.value.V2]; !alreadyComputed {
- cons := p.markMgates2(contextCircut, root.right, mGatesUsed, orderedmGates, Xor(negate, root.value.negate), Xor(inverse, root.value.invert))
- isConstant = isConstant || cons
- }
+ if _, alreadyComputed := mGatesUsed[root.value.V1]; !alreadyComputed {
+ isConstant = p.r1CSRecursiveBuild(currentCircuit, root.left, mGatesUsed, orderedmGates, negate, inverse)
+ }
+
+ if _, alreadyComputed := mGatesUsed[root.value.V2]; !alreadyComputed {
+ cons := p.r1CSRecursiveBuild(currentCircuit, root.right, mGatesUsed, orderedmGates, Xor(negate, root.value.negate), Xor(inverse, root.value.invert))
+ isConstant = isConstant || cons
}
if root.OperationType() == MULTIPLY {
- _, n, _ := isFunction(root.value.Out)
- if isConstant && !root.value.invert && n != "main" {
+ if isConstant && !root.value.invert && root != p.getMainCircuit().root {
return false
}
- root.leftIns = p.collectAtomsInSubtree2(contextCircut, root.left, mGatesUsed, false, false)
+ root.leftIns = p.collectFactors(currentCircuit, root.left, mGatesUsed, false, false)
//if root.left.value.Out== root.right.value.Out{
// //note this is not a full copy, but shouldnt be a problem
// root.rightIns= root.leftIns
@@ -177,10 +145,16 @@ func (p *Program) markMgates2(contextCircut *Circuit, root *gate, mGatesUsed map
// collectAtomsInSubtree(root.right, mGatesUsed, 1, root.rightIns, functionRootMap, Xor(negate, root.value.negate), Xor(inverse, root.value.invert))
//}
//root.rightIns = collectAtomsInSubtree3(root.right, mGatesUsed, Xor(negate, root.value.negate), Xor(inverse, root.value.invert))
- root.rightIns = p.collectAtomsInSubtree2(contextCircut, root.right, mGatesUsed, false, false)
+ root.rightIns = p.collectFactors(currentCircuit, root.right, mGatesUsed, false, false)
root.index = len(mGatesUsed)
- mGatesUsed[root.value.Out] = true
+ var nn = root.value.Out
+ //if _, ex := p.functions[nn]; ex {
+ // nn = composeNewFunction(root.value.Out, currentCircuit.Inputs)
+ //}
+
+ mGatesUsed[nn] = true
rootGate := cloneGate(root)
+ rootGate.value.Out = nn
*orderedmGates = append(*orderedmGates, *rootGate)
}
@@ -260,10 +234,12 @@ func abs(n int) (val int, positive bool) {
//returns the reduced sum of two input factor arrays
//if no reduction was done (worst case), it returns the concatenation of the input arrays
-func addFactors(leftFactors, rightFactors []factor) (res []factor) {
+func addFactors(leftFactors, rightFactors []factor) []factor {
var found bool
+ res := make([]factor, 0, len(leftFactors)+len(rightFactors))
for _, facLeft := range leftFactors {
+ found = false
for i, facRight := range rightFactors {
if facLeft.typ&facRight.typ == CONST {
@@ -274,8 +250,10 @@ func addFactors(leftFactors, rightFactors []factor) (res []factor) {
if facRight.negate {
b0 *= -1
}
- absValue, negate := abs(a0*facRight.multiplicative[1] + facLeft.multiplicative[1]*b0)
- rightFactors[i] = factor{typ: CONST, negate: negate, multiplicative: [2]int{absValue, facLeft.multiplicative[1] * facRight.multiplicative[1]}}
+ absValue, positive := abs(a0*facRight.multiplicative[1] + facLeft.multiplicative[1]*b0)
+
+ rightFactors[i] = factor{typ: CONST, negate: !positive, multiplicative: [2]int{absValue, facLeft.multiplicative[1] * facRight.multiplicative[1]}}
+
found = true
//res = append(res, factor{typ: CONST, negate: negate, multiplicative: [2]int{absValue, facLeft.multiplicative[1] * facRight.multiplicative[1]}})
break
@@ -288,8 +266,10 @@ func addFactors(leftFactors, rightFactors []factor) (res []factor) {
if facRight.negate {
b0 *= -1
}
- absValue, negate := abs(a0*facRight.multiplicative[1] + facLeft.multiplicative[1]*b0)
- rightFactors[i] = factor{typ: IN, invert: facRight.invert, name: facRight.name, negate: negate, multiplicative: [2]int{absValue, facLeft.multiplicative[1] * facRight.multiplicative[1]}}
+ absValue, positive := abs(a0*facRight.multiplicative[1] + facLeft.multiplicative[1]*b0)
+
+ rightFactors[i] = factor{typ: IN, invert: facRight.invert, name: facRight.name, negate: !positive, multiplicative: [2]int{absValue, facLeft.multiplicative[1] * facRight.multiplicative[1]}}
+
found = true
//res = append(res, factor{typ: CONST, negate: negate, multiplicative: [2]int{absValue, facLeft.multiplicative[1] * facRight.multiplicative[1]}})
break
@@ -297,13 +277,19 @@ func addFactors(leftFactors, rightFactors []factor) (res []factor) {
}
if !found {
res = append(res, facLeft)
- found = false
}
}
- return append(res, rightFactors...)
+
+ for _, val := range rightFactors {
+ if val.multiplicative[0] != 0 {
+ res = append(res, val)
+ }
+ }
+
+ return res
}
-func (p *Program) collectAtomsInSubtree2(contextCircut *Circuit, g *gate, mGatesUsed map[string]bool, negate bool, invert bool) []factor {
+func (p *Program) collectFactors(contextCircut *Circuit, g *gate, mGatesUsed map[string]bool, negate bool, invert bool) []factor {
if _, ex := mGatesUsed[g.value.Out]; ex {
return []factor{{typ: IN, name: g.value.Out, invert: invert, negate: negate, multiplicative: [2]int{1, 1}}}
@@ -314,7 +300,7 @@ func (p *Program) collectAtomsInSubtree2(contextCircut *Circuit, g *gate, mGates
}
if g.OperationType() == FUNC {
nextContext := p.extendedFunctionRenamer(contextCircut, g.value)
- return p.collectAtomsInSubtree2(nextContext, nextContext.root, mGatesUsed, negate, invert)
+ return p.collectFactors(nextContext, nextContext.root, mGatesUsed, negate, invert)
}
if g.OperationType() == CONST {
@@ -331,16 +317,16 @@ func (p *Program) collectAtomsInSubtree2(contextCircut *Circuit, g *gate, mGates
var leftFactors, rightFactors []factor
if g.left.OperationType() == FUNC {
nextContext := p.extendedFunctionRenamer(contextCircut, g.left.value)
- leftFactors = p.collectAtomsInSubtree2(nextContext, nextContext.root, mGatesUsed, negate, invert)
+ leftFactors = p.collectFactors(nextContext, nextContext.root, mGatesUsed, negate, invert)
} else {
- leftFactors = p.collectAtomsInSubtree2(contextCircut, g.left, mGatesUsed, negate, invert)
+ leftFactors = p.collectFactors(contextCircut, g.left, mGatesUsed, negate, invert)
}
if g.right.OperationType() == FUNC {
nextContext := p.extendedFunctionRenamer(contextCircut, g.right.value)
- rightFactors = p.collectAtomsInSubtree2(nextContext, nextContext.root, mGatesUsed, Xor(negate, g.value.negate), Xor(invert, g.value.invert))
+ rightFactors = p.collectFactors(nextContext, nextContext.root, mGatesUsed, Xor(negate, g.value.negate), Xor(invert, g.value.invert))
} else {
- rightFactors = p.collectAtomsInSubtree2(contextCircut, g.right, mGatesUsed, Xor(negate, g.value.negate), Xor(invert, g.value.invert))
+ rightFactors = p.collectFactors(contextCircut, g.right, mGatesUsed, Xor(negate, g.value.negate), Xor(invert, g.value.invert))
}
switch g.OperationType() {
@@ -356,7 +342,7 @@ func (p *Program) collectAtomsInSubtree2(contextCircut *Circuit, g *gate, mGates
//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}
+ 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([]factor, len(in.rightIns))
nLeftInst := make([]factor, len(in.leftIns))
for k, v := range in.rightIns {
@@ -368,11 +354,12 @@ func cloneGate(in *gate) (out *gate) {
return &gate{value: constr, leftIns: nLeftInst, rightIns: nRightins, index: in.index}
}
-func (p *Program) getMainCircut() *Circuit {
+func (p *Program) getMainCircuit() *Circuit {
return p.functions["main"]
}
func (p *Program) addGlobalInput(c Constraint) {
+ c.Out = "main@" + c.Out
p.globalInputs = append(p.globalInputs, c)
}
@@ -392,47 +379,56 @@ func prepareUtils() utils {
PF: pf,
}
}
-func NewProgramm() *Program {
-
- //return &Program{functions: map[string]*Circuit{}, signals: []string{}, globalInputs: []*Constraint{{Op: PLUS, V1:"1",V2:"0", Out: "one"}}}
- return &Program{functions: map[string]*Circuit{}, globalInputs: []Constraint{{Op: IN, Out: "one"}}, arithmeticEnvironment: prepareUtils()}
-}
-
-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
+func (p *Program) extendedFunctionRenamer(contextCircuit *Circuit, constraint *Constraint) (nextContext *Circuit) {
- if _, ex := p.functions[name]; ex {
- panic("function already declared")
+ if constraint.Op != FUNC {
+ panic("not a function")
}
-
- c = newCircuit(name)
-
- p.functions[name] = c
-
- //I need the inputs to be defined as input constraints for each function for later renaming conventions
- //if constraint.Literal == "main" {
- for _, in := range constraint.Inputs {
- newConstr := Constraint{
- Op: IN,
- Out: in,
- }
- if name == "main" {
- p.addGlobalInput(newConstr)
+ //if _, ex := contextCircuit.gateMap[constraint.Out]; !ex {
+ // panic("constraint must be within the contextCircuit circuit")
+ //}
+ if b, n, _ := isFunction(constraint.Out); b {
+ if newContext, v := p.functions[n]; v {
+ //am i certain that constraint.inputs is alwazs equal to n??? me dont like it
+ for i, argument := range constraint.Inputs {
+ isConst, _ := isValue(argument)
+ if isConst {
+ continue
+ }
+ isFunc, _, _ := isFunction(argument)
+ if isFunc {
+ panic("functions as arguments no supported yet")
+ //p.extendedFunctionRenamer(contextCircuit,)
+ }
+ //at this point I assert that argument is a variable. This can become troublesome later
+ inputOriginCircuit := p.functions[getContextFromVariable(argument)]
+ if gate, ex := inputOriginCircuit.gateMap[argument]; ex {
+ oldGate := newContext.gateMap[newContext.Inputs[i]]
+ //we take the old gate which was nothing but a input
+ //and link this input to its constituents comming from the calling contextCircuit.
+ //i think this is pretty neat
+ oldGate.value = gate.value
+ oldGate.right = gate.right
+ oldGate.left = gate.left
+
+ } else {
+ panic("not expected")
+ }
+ }
+ newContext.renameInputs(constraint.Inputs)
+ return newContext
}
- c.addConstraint(newConstr)
+ } else {
+ panic("not expected")
}
- //}
- c.Inputs = constraint.Inputs
- return
+ return nil
+}
+func NewProgram() (p *Program) {
+ p = &Program{functions: map[string]*Circuit{}, globalInputs: []Constraint{{Op: IN, Out: "one"}}, arithmeticEnvironment: prepareUtils()}
+ return
}
// GenerateR1CS generates the R1CS polynomials from the Circuit
@@ -496,11 +492,17 @@ func fractionToField(in [2]int) *big.Int {
}
func convertAndInsertFactorAt(arr []*big.Int, val factor, index int) {
+ value := new(big.Int).Add(new(big.Int), fractionToField(val.multiplicative))
+
+ if val.negate {
+ value.Neg(value)
+ }
+
if val.typ == CONST {
- arr[0] = new(big.Int).Add(arr[0], fractionToField(val.multiplicative))
- return
+ arr[0] = value
+ } else {
+ arr[index] = value
}
- arr[index] = new(big.Int).Add(arr[index], fractionToField(val.multiplicative))
}
diff --git a/circuitcompiler/Programm_test.go b/circuitcompiler/Programm_test.go
index 0428f07..54cda80 100644
--- a/circuitcompiler/Programm_test.go
+++ b/circuitcompiler/Programm_test.go
@@ -15,35 +15,35 @@ func TestProgramm_BuildConstraintTree(t *testing.T) {
func TestNewProgramm(t *testing.T) {
- flat := `
- func do(x):
- e = x * 5
- b = e * 6
- c = b * 7
- f = c * 1
- d = c * f
- out = d * mul(d,e)
-
- func add(x ,k):
- z = k * x
- out = do(x) + mul(x,z)
-
- func main(x,z):
- out = do(z) + add(x,x)
-
- func mul(a,b):
- out = a * b
- `
//flat := `
+ //func do(x):
+ // e = x * 5
+ // b = e * 6
+ // c = b * 7
+ // f = c * 1
+ // d = c * f
+ // out = d * mul(d,e)
+ //
+ //func add(x ,k):
+ // z = k * x
+ // out = do(x) + mul(x,z)
+ //
+ //func main(x,z):
+ // out = do(z) + add(x,x)
+ //
//func mul(a,b):
// out = a * b
- //
- //func main(a):
- // b = a * a
- // c = 4 - b
- // d = 5 * c
- // out = d / mul(b,b)
//`
+ flat := `
+ func mul(a,b):
+ out = a * b
+
+ func main(a):
+ b = a * a
+ c = 4 - b
+ d = 5 * c
+ out = mul(d,b) / mul(b,b)
+ `
//flat := `
//func main(a,b):
// c = a + b
@@ -80,8 +80,8 @@ func TestNewProgramm(t *testing.T) {
fmt.Println(b)
fmt.Println(c)
a1 := big.NewInt(int64(6))
- a2 := big.NewInt(int64(5))
- inputs := []*big.Int{a1, a2}
+ //a2 := big.NewInt(int64(5))
+ inputs := []*big.Int{a1}
w := program.CalculateWitness(inputs)
fmt.Println("witness")
fmt.Println(w)
diff --git a/circuitcompiler/circuit.go b/circuitcompiler/circuit.go
index 09abe98..56d9555 100644
--- a/circuitcompiler/circuit.go
+++ b/circuitcompiler/circuit.go
@@ -9,6 +9,8 @@ import (
"strings"
)
+var variableIndicationSign = "@"
+
// Circuit is the data structure of the compiled circuit
type Circuit struct {
Inputs []string
@@ -24,8 +26,8 @@ type gate struct {
left *gate
right *gate
funcInputs []*gate
- value Constraint //is a pointer a good thing here??
- leftIns []factor //leftIns and RightIns after addition gates have been reduced. only multiplication gates remain
+ value *Constraint //is a pointer a good thing here??
+ leftIns []factor //leftIns and RightIns after addition gates have been reduced. only multiplication gates remain
rightIns []factor
}
@@ -48,6 +50,7 @@ type Constraint struct {
//fV2 *variable
//fOut *variable
//Literal string
+ //TODO once i've implemented a new parser/lexer we do this differently
Inputs []string // in func declaration case
//fInputs []*variable
negate bool
@@ -65,15 +68,56 @@ func newCircuit(name string) *Circuit {
return &Circuit{Name: name, gateMap: make(map[string]*gate)}
}
-func (circ *Circuit) addConstraint(constraint Constraint) {
+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
+
+ renamedInputs := make([]string, len(constraint.Inputs))
+ //I need the inputs to be defined as input constraints for each function for later renaming conventions
+ //if constraint.Literal == "main" {
+ for i, in := range constraint.Inputs {
+ newConstr := &Constraint{
+ Op: IN,
+ Out: in,
+ }
+ if name == "main" {
+ p.addGlobalInput(*newConstr)
+ }
+ c.addConstraint(newConstr)
+ renamedInputs[i] = newConstr.Out
+ }
+ //}
+
+ c.Inputs = renamedInputs
+ return
+
+}
+
+func (circ *Circuit) addConstraint(constraint *Constraint) {
if _, ex := circ.gateMap[constraint.Out]; ex {
panic("already used FlatConstraint")
}
+ gateToAdd := &gate{value: constraint}
if constraint.Op == DIVIDE {
constraint.Op = MULTIPLY
constraint.invert = true
- } else if constraint.Op == MINUS {
+ }
+ if constraint.Op == MINUS {
constraint.Op = PLUS
constraint.negate = true
}
@@ -81,47 +125,40 @@ func (circ *Circuit) addConstraint(constraint Constraint) {
//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: "1", V2: "out2", Op: MULTIPLY}
- //TODO reachable?
- delete(circ.gateMap, constraint.Out)
- circ.addConstraint(newOut)
- constraint.Out = "out2"
- circ.addConstraint(constraint)
- }
- }
+ circ.root = gateToAdd
+ } else {
+ constraint.Out = circ.renamer(constraint.Out)
}
- addConstantsAndFunctions := func(constraint string) {
- if b, _ := isValue(constraint); b {
- circ.gateMap[constraint] = &gate{value: 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.gateMap[in] = &gate{value: Constraint{Op: CONST, Out: in}}
- continue
- }
- //if the argument is not in the constraint map, we panic. I used to do this later, but since we have a line
- //interpreter, we can do this here
- //the downside is that there cannot be functions passed as arguments
- //if _, ex := circ.constraintMap[in];!ex {
- // panic("undefined argument")
- //
- //}
- }
- circ.gateMap[constraint] = &gate{value: Constraint{Op: FUNC, Out: constraint, Inputs: inputs}}
+ constraint.V1 = circ.renamer(constraint.V1)
+ constraint.V2 = circ.renamer(constraint.V2)
+
+ circ.gateMap[constraint.Out] = gateToAdd
+}
+
+func (circ *Circuit) renamer(constraint string) string {
+
+ if constraint == "" {
+ return ""
+ }
+
+ if b, _ := isValue(constraint); b {
+ circ.gateMap[constraint] = &gate{value: &Constraint{Op: CONST, Out: constraint}}
+ return constraint
+ }
+
+ if b, name, inputs := isFunction(constraint); b {
+ renamedInputs := make([]string, len(inputs))
+ for i, in := range inputs {
+ renamedInputs[i] = circ.renamer(in)
}
+ nn := composeNewFunction(name, renamedInputs)
+ circ.gateMap[nn] = &gate{value: &Constraint{Op: FUNC, Out: nn, Inputs: renamedInputs}}
+ return nn
}
- addConstantsAndFunctions(constraint.V1)
- addConstantsAndFunctions(constraint.V2)
+ return circ.Name + variableIndicationSign + constraint
- circ.gateMap[constraint.Out] = &gate{value: constraint}
}
func (circ *Circuit) renameInputs(inputs []string) {
@@ -185,6 +222,13 @@ func (circ *Circuit) renameInputs(inputs []string) {
return
}
+func getContextFromVariable(in string) string {
+ if strings.Contains(in, variableIndicationSign) {
+ return strings.Split(in, variableIndicationSign)[0]
+ }
+ return ""
+}
+
func composeNewFunction(fname string, inputs []string) string {
builder := strings.Builder{}
builder.WriteString(fname)
diff --git a/circuitcompiler/circuit_test.go b/circuitcompiler/circuit_test.go
index c0fe98f..3e69dc9 100644
--- a/circuitcompiler/circuit_test.go
+++ b/circuitcompiler/circuit_test.go
@@ -39,7 +39,7 @@ func TestCircuitParser(t *testing.T) {
//`
//parser := NewParser(strings.NewReader(flat))
//programm, err := parser.Parse()
- //circuit := programm.getMainCircut()
+ //circuit := programm.getMainCircuit()
//assert.Nil(t, err)
//fmt.Println("\n unreduced")
//fmt.Println(flat)
diff --git a/circuitcompiler/parser.go b/circuitcompiler/parser.go
index 39a34c2..3905684 100644
--- a/circuitcompiler/parser.go
+++ b/circuitcompiler/parser.go
@@ -142,7 +142,7 @@ func addToArrayIfNotExist(arr []string, elem string) []string {
// Parse parses the lines and returns the compiled Circuit
func (p *Parser) Parse() (programm *Program, err error) {
- programm = NewProgramm()
+ programm = NewProgram()
var circuit *Circuit
@@ -154,7 +154,7 @@ func (p *Parser) Parse() (programm *Program, err error) {
if constraint.Op == FUNC {
circuit = programm.addFunction(constraint)
} else {
- circuit.addConstraint(*constraint)
+ circuit.addConstraint(constraint)
}
}
//TODO
diff --git a/r1csqap/r1csqap.go b/r1csqap/r1csqap.go
index 2a4d1c6..8836eec 100644
--- a/r1csqap/r1csqap.go
+++ b/r1csqap/r1csqap.go
@@ -24,9 +24,9 @@ func Transpose(matrix [][]*big.Int) [][]*big.Int {
// ArrayOfBigZeros creates a *big.Int array with n elements to zero
func ArrayOfBigZeros(num int) []*big.Int {
bigZero := big.NewInt(int64(0))
- var r []*big.Int
+ var r = make([]*big.Int, num, num)
for i := 0; i < num; i++ {
- r = append(r, bigZero)
+ r[i] = bigZero
}
return r
}