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.

361 lines
8.5 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: "one", V2: "out2", Op: MULTIPLY}
  101. delete(circ.constraintMap, constraint.Out)
  102. circ.addConstraint(newOut)
  103. constraint.Out = "out2"
  104. circ.addConstraint(constraint)
  105. }
  106. }
  107. }
  108. addConstantsAndFunctions := func(constraint string) {
  109. if b, _ := isValue(constraint); b {
  110. circ.constraintMap[constraint] = &Constraint{Op: CONST, Out: constraint}
  111. } else if b, _, inputs := isFunction(constraint); b {
  112. //check if function input is a constant like foo(a,4)
  113. for _, in := range inputs {
  114. if b, _ := isValue(in); b {
  115. circ.constraintMap[in] = &Constraint{Op: CONST, Out: in}
  116. }
  117. }
  118. circ.constraintMap[constraint] = &Constraint{Op: FUNC, Out: constraint, Inputs: inputs}
  119. }
  120. }
  121. addConstantsAndFunctions(constraint.V1)
  122. addConstantsAndFunctions(constraint.V2)
  123. circ.constraintMap[constraint.Out] = constraint
  124. }
  125. func (circ *Circuit) renameInputs(inputs []string) {
  126. if len(inputs) != len(circ.Inputs) {
  127. panic("given inputs != circuit.Inputs")
  128. }
  129. mapping := make(map[string]string)
  130. for i := 0; i < len(inputs); i++ {
  131. if _, ex := circ.constraintMap[inputs[i]]; ex {
  132. //this is a tricky part. So we replace former inputs with the new ones, thereby
  133. //it might be, that the new input name has already been used for some output inside the function
  134. //currently I dont know an elegant way how to handle this renaming issue
  135. if circ.constraintMap[inputs[i]].Op != IN {
  136. panic(fmt.Sprintf("renaming collsion with %s", inputs[i]))
  137. }
  138. }
  139. mapping[circ.Inputs[i]] = inputs[i]
  140. }
  141. //fmt.Println(mapping)
  142. circ.Inputs = inputs
  143. permute := func(in string) string {
  144. if out, ex := mapping[in]; ex {
  145. return out
  146. }
  147. return in
  148. }
  149. permuteListe := func(in []string) []string {
  150. for i := 0; i < len(in); i++ {
  151. in[i] = permute(in[i])
  152. }
  153. return in
  154. }
  155. for _, constraint := range circ.constraintMap {
  156. if constraint.Op == IN {
  157. constraint.Out = permute(constraint.Out)
  158. continue
  159. }
  160. if b, n, in := isFunction(constraint.Out); b {
  161. constraint.Out = composeNewFunction(n, permuteListe(in))
  162. constraint.Inputs = permuteListe(in)
  163. }
  164. if b, n, in := isFunction(constraint.V1); b {
  165. constraint.V1 = composeNewFunction(n, permuteListe(in))
  166. constraint.Inputs = permuteListe(in)
  167. }
  168. if b, n, in := isFunction(constraint.V2); b {
  169. constraint.V2 = composeNewFunction(n, permuteListe(in))
  170. constraint.Inputs = permuteListe(in)
  171. }
  172. constraint.V1 = permute(constraint.V1)
  173. constraint.V2 = permute(constraint.V2)
  174. }
  175. return
  176. }
  177. func composeNewFunction(fname string, inputs []string) string {
  178. builder := strings.Builder{}
  179. builder.WriteString(fname)
  180. builder.WriteRune('(')
  181. for i := 0; i < len(inputs); i++ {
  182. builder.WriteString(inputs[i])
  183. if i < len(inputs)-1 {
  184. builder.WriteRune(',')
  185. }
  186. }
  187. builder.WriteRune(')')
  188. return builder.String()
  189. }
  190. func max(a, b int) int {
  191. if a > b {
  192. return a
  193. }
  194. return b
  195. }
  196. func TreeDepth(g *gate) int {
  197. return printDepth(g, 0)
  198. }
  199. func printDepth(g *gate, d int) int {
  200. d = d + 1
  201. if g.left != nil && g.right != nil {
  202. return max(printDepth(g.left, d), printDepth(g.right, d))
  203. } else if g.left != nil {
  204. return printDepth(g.left, d)
  205. } else if g.right != nil {
  206. return printDepth(g.right, d)
  207. }
  208. return d
  209. }
  210. func CountMultiplicationGates(g *gate) int {
  211. if g == nil {
  212. return 0
  213. }
  214. if len(g.rightIns) > 0 || len(g.leftIns) > 0 {
  215. return 1 + CountMultiplicationGates(g.left) + CountMultiplicationGates(g.right)
  216. } else {
  217. return CountMultiplicationGates(g.left) + CountMultiplicationGates(g.right)
  218. }
  219. return 0
  220. }
  221. //TODO avoid printing multiple times in case of loops
  222. func PrintTree(g *gate) {
  223. printTree(g, 0)
  224. }
  225. func printTree(g *gate, d int) {
  226. d += 1
  227. if g.leftIns == nil || g.rightIns == nil {
  228. fmt.Printf("Depth: %v - %s \t \t \t \t \n", d, g.value)
  229. } else {
  230. fmt.Printf("Depth: %v - %s \t \t \t \t with l %v and r %v\n", d, g.value, g.leftIns, g.rightIns)
  231. }
  232. if g.funcInputs != nil {
  233. for _, v := range g.funcInputs {
  234. printTree(v, d)
  235. }
  236. }
  237. if g.left != nil {
  238. printTree(g.left, d)
  239. }
  240. if g.right != nil {
  241. printTree(g.right, d)
  242. }
  243. }
  244. func addToMap(value string, in map[string]int, negate bool) {
  245. if negate {
  246. in[value] = in[value] - 1
  247. } else {
  248. in[value] = in[value] + 1
  249. }
  250. }
  251. func collectAtomsInSubtree(g *gate, in map[string]int, functionRootMap map[string]*gate, negate bool, invert bool) {
  252. if g == nil {
  253. return
  254. }
  255. if g.OperationType()&(MULTIPLY|IN|CONST) != 0 {
  256. addToMap(g.value.Out, in, negate)
  257. return
  258. }
  259. if g.OperationType() == FUNC {
  260. if b, name, _ := isFunction(g.value.Out); b {
  261. collectAtomsInSubtree(functionRootMap[name], in, functionRootMap, negate, invert)
  262. } else {
  263. panic("function expected")
  264. }
  265. }
  266. collectAtomsInSubtree(g.left, in, functionRootMap, negate, invert)
  267. collectAtomsInSubtree(g.right, in, functionRootMap, Xor(negate, g.value.negate), invert)
  268. }
  269. func Xor(a, b bool) bool {
  270. return (a && !b) || (!a && b)
  271. }
  272. func (g *gate) ExtractValues(in []int) (er error) {
  273. if b, v1 := isValue(g.value.V1); b {
  274. if b2, v2 := isValue(g.value.V2); b2 {
  275. in = append(in, v1, v2)
  276. return nil
  277. }
  278. }
  279. return errors.New(fmt.Sprintf("Gate \"%s\" has no int values", g.value))
  280. }
  281. func (g *gate) OperationType() Token {
  282. return g.value.Op
  283. }
  284. //returns index of e if its in arr
  285. //return -1 if e not in arr
  286. func indexInArray(arr []string, e string) int {
  287. for i, a := range arr {
  288. if a == e {
  289. return i
  290. }
  291. }
  292. panic("lul")
  293. return -1
  294. }
  295. func isValue(a string) (bool, int) {
  296. v, err := strconv.Atoi(a)
  297. if err != nil {
  298. return false, 0
  299. }
  300. return true, v
  301. }
  302. func isFunction(a string) (tf bool, name string, inputs []string) {
  303. if !strings.ContainsRune(a, '(') && !strings.ContainsRune(a, ')') {
  304. return false, "", nil
  305. }
  306. name = strings.Split(a, "(")[0]
  307. // read string inside ( )
  308. rgx := regexp.MustCompile(`\((.*?)\)`)
  309. insideParenthesis := rgx.FindStringSubmatch(a)
  310. varsString := strings.Replace(insideParenthesis[1], " ", "", -1)
  311. inputs = strings.Split(varsString, ",")
  312. return true, name, inputs
  313. }
  314. type Inputs struct {
  315. Private []*big.Int
  316. Publics []*big.Int
  317. }