You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

334 lines
7.8 KiB

  1. package circuitcompiler
  2. import (
  3. "errors"
  4. "fmt"
  5. "math/big"
  6. "regexp"
  7. "strconv"
  8. "strings"
  9. )
  10. // Circuit is the data structure of the compiled circuit
  11. type Circuit struct {
  12. NVars int
  13. NPublic int
  14. NSignals int
  15. Inputs []string
  16. Signals []string
  17. PublicSignals []string
  18. Witness []*big.Int
  19. Name string
  20. root *gate
  21. //after reducing
  22. constraintMap map[string]*Constraint
  23. //used map[string]bool
  24. R1CS struct {
  25. A [][]*big.Int
  26. B [][]*big.Int
  27. C [][]*big.Int
  28. }
  29. }
  30. type gate struct {
  31. index int
  32. left *gate
  33. right *gate
  34. funcInputs []*gate
  35. value *Constraint
  36. leftIns map[string]int //leftIns and RightIns after addition gates have been reduced. only multiplication gates remain
  37. rightIns map[string]int
  38. }
  39. func (g gate) String() string {
  40. return fmt.Sprintf("Gate %v : %v with left %v right %v", g.index, g.value, g.leftIns, g.rightIns)
  41. }
  42. //type variable struct {
  43. // val string
  44. //}
  45. // Constraint is the data structure of a flat code operation
  46. type Constraint struct {
  47. // v1 op v2 = out
  48. Op Token
  49. V1 string
  50. V2 string
  51. Out string
  52. //fV1 *variable
  53. //fV2 *variable
  54. //fOut *variable
  55. //Literal string
  56. Inputs []string // in func declaration case
  57. //fInputs []*variable
  58. negate bool
  59. invert bool
  60. }
  61. func (c Constraint) String() string {
  62. if c.negate || c.invert {
  63. return fmt.Sprintf("|%v = %v %v %v| negated: %v, inverted %v", c.Out, c.V1, c.Op, c.V2, c.negate, c.invert)
  64. }
  65. return fmt.Sprintf("|%v = %v %v %v|", c.Out, c.V1, c.Op, c.V2)
  66. }
  67. func newCircuit(name string) *Circuit {
  68. return &Circuit{Name: name, constraintMap: make(map[string]*Constraint)}
  69. }
  70. func (g *gate) addLeft(c *Constraint) {
  71. if g.left != nil {
  72. panic("already set left gate")
  73. }
  74. g.left = &gate{value: c}
  75. }
  76. func (g *gate) addRight(c *Constraint) {
  77. if g.right != nil {
  78. panic("already set left gate")
  79. }
  80. g.right = &gate{value: c}
  81. }
  82. func (circ *Circuit) addConstraint(constraint *Constraint) {
  83. if _, ex := circ.constraintMap[constraint.Out]; ex {
  84. panic("already used FlatConstraint")
  85. }
  86. if constraint.Op == DIVIDE {
  87. constraint.Op = MULTIPLY
  88. constraint.invert = true
  89. } else if constraint.Op == MINUS {
  90. constraint.Op = PLUS
  91. constraint.negate = true
  92. }
  93. //todo this is dangerous.. if someone would use out as variable name, things would be fucked
  94. if constraint.Out == "out" {
  95. constraint.Out = composeNewFunction(circ.Name, circ.Inputs)
  96. if circ.Name == "main" {
  97. //the main functions output must be a multiplication gate
  98. //if its not, then we simple create one where outNew = 1 * outOld
  99. if constraint.Op&(MINUS|PLUS) != 0 {
  100. newOut := &Constraint{Out: constraint.Out, V1: "1", V2: "out2", Op: MULTIPLY}
  101. //TODO reachable?
  102. delete(circ.constraintMap, constraint.Out)
  103. circ.addConstraint(newOut)
  104. constraint.Out = "out2"
  105. circ.addConstraint(constraint)
  106. }
  107. }
  108. }
  109. addConstantsAndFunctions := func(constraint string) {
  110. if b, _ := isValue(constraint); b {
  111. circ.constraintMap[constraint] = &Constraint{Op: CONST, Out: constraint}
  112. } else if b, _, inputs := isFunction(constraint); b {
  113. //check if function input is a constant like foo(a,4)
  114. for _, in := range inputs {
  115. if b, _ := isValue(in); b {
  116. circ.constraintMap[in] = &Constraint{Op: CONST, Out: in}
  117. }
  118. }
  119. circ.constraintMap[constraint] = &Constraint{Op: FUNC, Out: constraint, Inputs: inputs}
  120. }
  121. }
  122. addConstantsAndFunctions(constraint.V1)
  123. addConstantsAndFunctions(constraint.V2)
  124. circ.constraintMap[constraint.Out] = constraint
  125. }
  126. func (circ *Circuit) renameInputs(inputs []string) {
  127. if len(inputs) != len(circ.Inputs) {
  128. panic("given inputs != circuit.Inputs")
  129. }
  130. mapping := make(map[string]string)
  131. for i := 0; i < len(inputs); i++ {
  132. if _, ex := circ.constraintMap[inputs[i]]; ex {
  133. //this is a tricky part. So we replace former inputs with the new ones, thereby
  134. //it might be, that the new input name has already been used for some output inside the function
  135. //currently I dont know an elegant way how to handle this renaming issue
  136. if circ.constraintMap[inputs[i]].Op != IN {
  137. panic(fmt.Sprintf("renaming collsion with %s", inputs[i]))
  138. }
  139. }
  140. mapping[circ.Inputs[i]] = inputs[i]
  141. }
  142. //fmt.Println(mapping)
  143. circ.Inputs = inputs
  144. permute := func(in string) string {
  145. if out, ex := mapping[in]; ex {
  146. return out
  147. }
  148. return in
  149. }
  150. permuteListe := func(in []string) []string {
  151. for i := 0; i < len(in); i++ {
  152. in[i] = permute(in[i])
  153. }
  154. return in
  155. }
  156. for _, constraint := range circ.constraintMap {
  157. if constraint.Op == IN {
  158. constraint.Out = permute(constraint.Out)
  159. continue
  160. }
  161. if b, n, in := isFunction(constraint.Out); b {
  162. constraint.Out = composeNewFunction(n, permuteListe(in))
  163. constraint.Inputs = permuteListe(in)
  164. }
  165. if b, n, in := isFunction(constraint.V1); b {
  166. constraint.V1 = composeNewFunction(n, permuteListe(in))
  167. constraint.Inputs = permuteListe(in)
  168. }
  169. if b, n, in := isFunction(constraint.V2); b {
  170. constraint.V2 = composeNewFunction(n, permuteListe(in))
  171. constraint.Inputs = permuteListe(in)
  172. }
  173. constraint.V1 = permute(constraint.V1)
  174. constraint.V2 = permute(constraint.V2)
  175. }
  176. return
  177. }
  178. func composeNewFunction(fname string, inputs []string) string {
  179. builder := strings.Builder{}
  180. builder.WriteString(fname)
  181. builder.WriteRune('(')
  182. for i := 0; i < len(inputs); i++ {
  183. builder.WriteString(inputs[i])
  184. if i < len(inputs)-1 {
  185. builder.WriteRune(',')
  186. }
  187. }
  188. builder.WriteRune(')')
  189. return builder.String()
  190. }
  191. func max(a, b int) int {
  192. if a > b {
  193. return a
  194. }
  195. return b
  196. }
  197. func TreeDepth(g *gate) int {
  198. return printDepth(g, 0)
  199. }
  200. func printDepth(g *gate, d int) int {
  201. d = d + 1
  202. if g.left != nil && g.right != nil {
  203. return max(printDepth(g.left, d), printDepth(g.right, d))
  204. } else if g.left != nil {
  205. return printDepth(g.left, d)
  206. } else if g.right != nil {
  207. return printDepth(g.right, d)
  208. }
  209. return d
  210. }
  211. func CountMultiplicationGates(g *gate) int {
  212. if g == nil {
  213. return 0
  214. }
  215. if len(g.rightIns) > 0 || len(g.leftIns) > 0 {
  216. return 1 + CountMultiplicationGates(g.left) + CountMultiplicationGates(g.right)
  217. } else {
  218. return CountMultiplicationGates(g.left) + CountMultiplicationGates(g.right)
  219. }
  220. return 0
  221. }
  222. //TODO avoid printing multiple times in case of loops
  223. func PrintTree(g *gate) {
  224. printTree(g, 0)
  225. }
  226. func printTree(g *gate, d int) {
  227. d += 1
  228. if g.leftIns == nil || g.rightIns == nil {
  229. fmt.Printf("Depth: %v - %s \t \t \t \t \n", d, g.value)
  230. } else {
  231. fmt.Printf("Depth: %v - %s \t \t \t \t with l %v and r %v\n", d, g.value, g.leftIns, g.rightIns)
  232. }
  233. if g.funcInputs != nil {
  234. for _, v := range g.funcInputs {
  235. printTree(v, d)
  236. }
  237. }
  238. if g.left != nil {
  239. printTree(g.left, d)
  240. }
  241. if g.right != nil {
  242. printTree(g.right, d)
  243. }
  244. }
  245. func Xor(a, b bool) bool {
  246. return (a && !b) || (!a && b)
  247. }
  248. func (g *gate) ExtractValues(in []int) (er error) {
  249. if b, v1 := isValue(g.value.V1); b {
  250. if b2, v2 := isValue(g.value.V2); b2 {
  251. in = append(in, v1, v2)
  252. return nil
  253. }
  254. }
  255. return errors.New(fmt.Sprintf("Gate \"%s\" has no int values", g.value))
  256. }
  257. func (g *gate) OperationType() Token {
  258. return g.value.Op
  259. }
  260. //returns index of e if its in arr
  261. //return -1 if e not in arr
  262. func indexInArray(arr []string, e string) int {
  263. for i, a := range arr {
  264. if a == e {
  265. return i
  266. }
  267. }
  268. panic("lul")
  269. return -1
  270. }
  271. func isValue(a string) (bool, int) {
  272. v, err := strconv.Atoi(a)
  273. if err != nil {
  274. return false, 0
  275. }
  276. return true, v
  277. }
  278. func isFunction(a string) (tf bool, name string, inputs []string) {
  279. if !strings.ContainsRune(a, '(') && !strings.ContainsRune(a, ')') {
  280. return false, "", nil
  281. }
  282. name = strings.Split(a, "(")[0]
  283. // read string inside ( )
  284. rgx := regexp.MustCompile(`\((.*?)\)`)
  285. insideParenthesis := rgx.FindStringSubmatch(a)
  286. varsString := strings.Replace(insideParenthesis[1], " ", "", -1)
  287. inputs = strings.Split(varsString, ",")
  288. return true, name, inputs
  289. }
  290. type Inputs struct {
  291. Private []*big.Int
  292. Publics []*big.Int
  293. }