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
 11type Circuit struct {
 12	NVars       int
 13	NPublic     int
 14	NSignals    int
 15	Inputs      []string
 16	Signals     []string
 17	Witness     []*big.Int
 18	Constraints []Constraint
 19	R1CS        struct {
 20		A [][]*big.Int
 21		B [][]*big.Int
 22		C [][]*big.Int
 23	}
 24}
 25type Constraint struct {
 26	// v1 op v2 = out
 27	Op      string
 28	V1      string
 29	V2      string
 30	Out     string
 31	Literal string
 32
 33	Inputs []string // in func delcaration case
 34}
 35
 36func indexInArray(arr []string, e string) int {
 37	for i, a := range arr {
 38		if a == e {
 39			return i
 40		}
 41	}
 42	return -1
 43}
 44func isValue(a string) (bool, int) {
 45	v, err := strconv.Atoi(a)
 46	if err != nil {
 47		return false, 0
 48	}
 49	return true, v
 50}
 51func insertVar(arr []*big.Int, signals []string, v string, used map[string]bool) ([]*big.Int, map[string]bool) {
 52	isVal, value := isValue(v)
 53	valueBigInt := big.NewInt(int64(value))
 54	if isVal {
 55		arr[0] = new(big.Int).Add(arr[0], valueBigInt)
 56	} else {
 57		if !used[v] {
 58			panic(errors.New("using variable before it's set"))
 59		}
 60		arr[indexInArray(signals, v)] = new(big.Int).Add(arr[indexInArray(signals, v)], big.NewInt(int64(1)))
 61	}
 62	return arr, used
 63}
 64
 65func (circ *Circuit) GenerateR1CS() ([][]*big.Int, [][]*big.Int, [][]*big.Int) {
 66	// from flat code to R1CS
 67
 68	var a [][]*big.Int
 69	var b [][]*big.Int
 70	var c [][]*big.Int
 71
 72	used := make(map[string]bool)
 73	for _, constraint := range circ.Constraints {
 74
 75		aConstraint := r1csqap.ArrayOfBigZeros(len(circ.Signals))
 76		bConstraint := r1csqap.ArrayOfBigZeros(len(circ.Signals))
 77		cConstraint := r1csqap.ArrayOfBigZeros(len(circ.Signals))
 78
 79		// if existInArray(constraint.Out) {
 80		if used[constraint.Out] {
 81			panic(errors.New("out variable already used: " + constraint.Out))
 82		}
 83		used[constraint.Out] = true
 84		if constraint.Op == "in" {
 85			for i := 0; i < len(constraint.Inputs); i++ {
 86				aConstraint[indexInArray(circ.Signals, constraint.Out)] = new(big.Int).Add(aConstraint[indexInArray(circ.Signals, constraint.Out)], big.NewInt(int64(1)))
 87				aConstraint, used = insertVar(aConstraint, circ.Signals, constraint.Out, used)
 88				bConstraint[0] = big.NewInt(int64(1))
 89
 90			}
 91			continue
 92
 93		} else if constraint.Op == "+" {
 94			cConstraint[indexInArray(circ.Signals, constraint.Out)] = big.NewInt(int64(1))
 95			aConstraint, used = insertVar(aConstraint, circ.Signals, constraint.V1, used)
 96			aConstraint, used = insertVar(aConstraint, circ.Signals, constraint.V2, used)
 97			bConstraint[0] = big.NewInt(int64(1))
 98		} else if constraint.Op == "*" {
 99			cConstraint[indexInArray(circ.Signals, constraint.Out)] = big.NewInt(int64(1))
100			aConstraint, used = insertVar(aConstraint, circ.Signals, constraint.V1, used)
101			bConstraint, used = insertVar(bConstraint, circ.Signals, constraint.V2, used)
102		}
103
104		a = append(a, aConstraint)
105		b = append(b, bConstraint)
106		c = append(c, cConstraint)
107
108	}
109	return a, b, c
110}