go-snark/circuitcompiler/circuit.go
circuitcompiler/circuit.goRaw
1package circuitcompiler
2
3import (
4 "errors"
5 "math/big"
6 "strconv"
7
8 "github.com/arnaucube/go-snark/r1csqap"
9)
10
11// Circuit is the data structure of the compiled circuit
12type Circuit struct {
13 NVars int
14 NPublic int
15 NSignals int
16 Inputs []string
17 Signals []string
18 Witness []*big.Int
19 Constraints []Constraint
20 R1CS struct {
21 A [][]*big.Int
22 B [][]*big.Int
23 C [][]*big.Int
24 }
25}
26
27// Constraint is the data structure of a flat code operation
28type Constraint struct {
29 // v1 op v2 = out
30 Op string
31 V1 string
32 V2 string
33 Out string
34 Literal string
35
36 Inputs []string // in func delcaration case
37}
38
39func indexInArray(arr []string, e string) int {
40 for i, a := range arr {
41 if a == e {
42 return i
43 }
44 }
45 return -1
46}
47func isValue(a string) (bool, int) {
48 v, err := strconv.Atoi(a)
49 if err != nil {
50 return false, 0
51 }
52 return true, v
53}
54func insertVar(arr []*big.Int, signals []string, v string, used map[string]bool) ([]*big.Int, map[string]bool) {
55 isVal, value := isValue(v)
56 valueBigInt := big.NewInt(int64(value))
57 if isVal {
58 arr[0] = new(big.Int).Add(arr[0], valueBigInt)
59 } else {
60 if !used[v] {
61 panic(errors.New("using variable before it's set"))
62 }
63 arr[indexInArray(signals, v)] = new(big.Int).Add(arr[indexInArray(signals, v)], big.NewInt(int64(1)))
64 }
65 return arr, used
66}
67func insertVarNeg(arr []*big.Int, signals []string, v string, used map[string]bool) ([]*big.Int, map[string]bool) {
68 isVal, value := isValue(v)
69 valueBigInt := big.NewInt(int64(value))
70 if isVal {
71 arr[0] = new(big.Int).Add(arr[0], valueBigInt)
72 } else {
73 if !used[v] {
74 panic(errors.New("using variable before it's set"))
75 }
76 arr[indexInArray(signals, v)] = new(big.Int).Add(arr[indexInArray(signals, v)], big.NewInt(int64(-1)))
77 }
78 return arr, used
79}
80
81// GenerateR1CS generates the R1CS polynomials from the Circuit
82func (circ *Circuit) GenerateR1CS() ([][]*big.Int, [][]*big.Int, [][]*big.Int) {
83 // from flat code to R1CS
84
85 var a [][]*big.Int
86 var b [][]*big.Int
87 var c [][]*big.Int
88
89 used := make(map[string]bool)
90 for _, constraint := range circ.Constraints {
91 aConstraint := r1csqap.ArrayOfBigZeros(len(circ.Signals))
92 bConstraint := r1csqap.ArrayOfBigZeros(len(circ.Signals))
93 cConstraint := r1csqap.ArrayOfBigZeros(len(circ.Signals))
94
95 // if existInArray(constraint.Out) {
96 if used[constraint.Out] {
97 panic(errors.New("out variable already used: " + constraint.Out))
98 }
99 used[constraint.Out] = true
100 if constraint.Op == "in" {
101 for i := 0; i < len(constraint.Inputs); i++ {
102 aConstraint[indexInArray(circ.Signals, constraint.Out)] = new(big.Int).Add(aConstraint[indexInArray(circ.Signals, constraint.Out)], big.NewInt(int64(1)))
103 aConstraint, used = insertVar(aConstraint, circ.Signals, constraint.Out, used)
104 bConstraint[0] = big.NewInt(int64(1))
105 }
106 continue
107
108 } else if constraint.Op == "+" {
109 cConstraint[indexInArray(circ.Signals, constraint.Out)] = big.NewInt(int64(1))
110 aConstraint, used = insertVar(aConstraint, circ.Signals, constraint.V1, used)
111 aConstraint, used = insertVar(aConstraint, circ.Signals, constraint.V2, used)
112 bConstraint[0] = big.NewInt(int64(1))
113 } else if constraint.Op == "-" {
114 cConstraint[indexInArray(circ.Signals, constraint.Out)] = big.NewInt(int64(1))
115 aConstraint, used = insertVarNeg(aConstraint, circ.Signals, constraint.V1, used)
116 aConstraint, used = insertVarNeg(aConstraint, circ.Signals, constraint.V2, used)
117 bConstraint[0] = big.NewInt(int64(1))
118 } else if constraint.Op == "*" {
119 cConstraint[indexInArray(circ.Signals, constraint.Out)] = big.NewInt(int64(1))
120 aConstraint, used = insertVar(aConstraint, circ.Signals, constraint.V1, used)
121 bConstraint, used = insertVar(bConstraint, circ.Signals, constraint.V2, used)
122 } else if constraint.Op == "/" {
123 cConstraint, used = insertVar(cConstraint, circ.Signals, constraint.V1, used)
124 cConstraint[indexInArray(circ.Signals, constraint.Out)] = big.NewInt(int64(1))
125 bConstraint, used = insertVar(bConstraint, circ.Signals, constraint.V2, used)
126 }
127
128 a = append(a, aConstraint)
129 b = append(b, bConstraint)
130 c = append(c, cConstraint)
131
132 }
133 return a, b, c
134}
135
136func grabVar(signals []string, w []*big.Int, vStr string) *big.Int {
137 isVal, v := isValue(vStr)
138 vBig := big.NewInt(int64(v))
139 if isVal {
140 return vBig
141 } else {
142 return w[indexInArray(signals, vStr)]
143 }
144}
145
146// CalculateWitness calculates the Witness of a Circuit based on the given inputs
147func (circ *Circuit) CalculateWitness(inputs []*big.Int) []*big.Int {
148 w := r1csqap.ArrayOfBigZeros(len(circ.Signals))
149 w[0] = big.NewInt(int64(1))
150 for i, input := range inputs {
151 w[i+1] = input
152 }
153 for _, constraint := range circ.Constraints {
154 if constraint.Op == "in" {
155 } else if constraint.Op == "+" {
156 w[indexInArray(circ.Signals, constraint.Out)] = new(big.Int).Add(grabVar(circ.Signals, w, constraint.V1), grabVar(circ.Signals, w, constraint.V2))
157 } else if constraint.Op == "-" {
158 w[indexInArray(circ.Signals, constraint.Out)] = new(big.Int).Sub(grabVar(circ.Signals, w, constraint.V1), grabVar(circ.Signals, w, constraint.V2))
159 } else if constraint.Op == "*" {
160 w[indexInArray(circ.Signals, constraint.Out)] = new(big.Int).Mul(grabVar(circ.Signals, w, constraint.V1), grabVar(circ.Signals, w, constraint.V2))
161 } else if constraint.Op == "/" {
162 w[indexInArray(circ.Signals, constraint.Out)] = new(big.Int).Div(grabVar(circ.Signals, w, constraint.V1), grabVar(circ.Signals, w, constraint.V2))
163 }
164 }
165 return w
166}