|
|
package circuitcompiler
import ( "errors" "math/big" "strconv"
"github.com/arnaucube/go-snark/r1csqap" )
// Circuit is the data structure of the compiled circuit
type Circuit struct { NVars int NPublic int NSignals int Inputs []string Signals []string Witness []*big.Int Constraints []Constraint R1CS struct { A [][]*big.Int B [][]*big.Int C [][]*big.Int } }
// Constraint is the data structure of a flat code operation
type Constraint struct { // v1 op v2 = out
Op string V1 string V2 string Out string Literal string
Inputs []string // in func declaration case
}
func indexInArray(arr []string, e string) int { for i, a := range arr { if a == e { return i } } return -1 } func isValue(a string) (bool, int) { v, err := strconv.Atoi(a) if err != nil { return false, 0 } return true, v } func insertVar(arr []*big.Int, signals []string, v string, used map[string]bool) ([]*big.Int, map[string]bool) { isVal, value := isValue(v) valueBigInt := big.NewInt(int64(value)) if isVal { arr[0] = new(big.Int).Add(arr[0], valueBigInt) } else { if !used[v] { panic(errors.New("using variable before it's set")) } arr[indexInArray(signals, v)] = new(big.Int).Add(arr[indexInArray(signals, v)], big.NewInt(int64(1))) } return arr, used } func insertVarNeg(arr []*big.Int, signals []string, v string, used map[string]bool) ([]*big.Int, map[string]bool) { isVal, value := isValue(v) valueBigInt := big.NewInt(int64(value)) if isVal { arr[0] = new(big.Int).Add(arr[0], valueBigInt) } else { if !used[v] { panic(errors.New("using variable before it's set")) } arr[indexInArray(signals, v)] = new(big.Int).Add(arr[indexInArray(signals, v)], big.NewInt(int64(-1))) } return arr, used }
// GenerateR1CS generates the R1CS polynomials from the Circuit
func (circ *Circuit) GenerateR1CS() ([][]*big.Int, [][]*big.Int, [][]*big.Int) { // from flat code to R1CS
var a [][]*big.Int var b [][]*big.Int var c [][]*big.Int
used := make(map[string]bool) for _, constraint := range circ.Constraints { aConstraint := r1csqap.ArrayOfBigZeros(len(circ.Signals)) bConstraint := r1csqap.ArrayOfBigZeros(len(circ.Signals)) cConstraint := r1csqap.ArrayOfBigZeros(len(circ.Signals))
// if existInArray(constraint.Out) {
if used[constraint.Out] { panic(errors.New("out variable already used: " + constraint.Out)) } used[constraint.Out] = true if constraint.Op == "in" { for i := 0; i < len(constraint.Inputs); i++ { aConstraint[indexInArray(circ.Signals, constraint.Out)] = new(big.Int).Add(aConstraint[indexInArray(circ.Signals, constraint.Out)], big.NewInt(int64(1))) aConstraint, used = insertVar(aConstraint, circ.Signals, constraint.Out, used) bConstraint[0] = big.NewInt(int64(1)) } continue
} else if constraint.Op == "+" { cConstraint[indexInArray(circ.Signals, constraint.Out)] = big.NewInt(int64(1)) aConstraint, used = insertVar(aConstraint, circ.Signals, constraint.V1, used) aConstraint, used = insertVar(aConstraint, circ.Signals, constraint.V2, used) bConstraint[0] = big.NewInt(int64(1)) } else if constraint.Op == "-" { cConstraint[indexInArray(circ.Signals, constraint.Out)] = big.NewInt(int64(1)) aConstraint, used = insertVarNeg(aConstraint, circ.Signals, constraint.V1, used) aConstraint, used = insertVarNeg(aConstraint, circ.Signals, constraint.V2, used) bConstraint[0] = big.NewInt(int64(1)) } else if constraint.Op == "*" { cConstraint[indexInArray(circ.Signals, constraint.Out)] = big.NewInt(int64(1)) aConstraint, used = insertVar(aConstraint, circ.Signals, constraint.V1, used) bConstraint, used = insertVar(bConstraint, circ.Signals, constraint.V2, used) } else if constraint.Op == "/" { cConstraint, used = insertVar(cConstraint, circ.Signals, constraint.V1, used) cConstraint[indexInArray(circ.Signals, constraint.Out)] = big.NewInt(int64(1)) bConstraint, used = insertVar(bConstraint, circ.Signals, constraint.V2, used) }
a = append(a, aConstraint) b = append(b, bConstraint) c = append(c, cConstraint)
} return a, b, c }
func grabVar(signals []string, w []*big.Int, vStr string) *big.Int { isVal, v := isValue(vStr) vBig := big.NewInt(int64(v)) if isVal { return vBig } else { return w[indexInArray(signals, vStr)] } }
// CalculateWitness calculates the Witness of a Circuit based on the given inputs
func (circ *Circuit) CalculateWitness(inputs []*big.Int) []*big.Int { w := r1csqap.ArrayOfBigZeros(len(circ.Signals)) w[0] = big.NewInt(int64(1)) for i, input := range inputs { w[i+1] = input } for _, constraint := range circ.Constraints { if constraint.Op == "in" { } else if constraint.Op == "+" { w[indexInArray(circ.Signals, constraint.Out)] = new(big.Int).Add(grabVar(circ.Signals, w, constraint.V1), grabVar(circ.Signals, w, constraint.V2)) } else if constraint.Op == "-" { w[indexInArray(circ.Signals, constraint.Out)] = new(big.Int).Sub(grabVar(circ.Signals, w, constraint.V1), grabVar(circ.Signals, w, constraint.V2)) } else if constraint.Op == "*" { w[indexInArray(circ.Signals, constraint.Out)] = new(big.Int).Mul(grabVar(circ.Signals, w, constraint.V1), grabVar(circ.Signals, w, constraint.V2)) } else if constraint.Op == "/" { w[indexInArray(circ.Signals, constraint.Out)] = new(big.Int).Div(grabVar(circ.Signals, w, constraint.V1), grabVar(circ.Signals, w, constraint.V2)) } } return w }
|