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.3 KiB

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