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