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