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.

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