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