qap.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. import numpy as np
  2. # Lets prove we know the answer to x**3 + x + 5 == 35 (x = 5)
  3. # We break it down into these statements:
  4. # L1: s1 = x * x
  5. # L2: y = s1 * x
  6. # L3: s2 = y + x
  7. # L4: out = s2 + 5
  8. # Statements are of the form:
  9. # a * b = c
  10. # s1 = x * x
  11. # OR a * b = c, where a = x, b = x and c = s1
  12. L1 = np.array([
  13. # a b c
  14. [0, 0, 0], # 1
  15. [1, 1, 0], # x
  16. [0, 0, 0], # out
  17. [0, 0, 1], # s1
  18. [0, 0, 0], # y
  19. [0, 0, 0] # s2
  20. ])
  21. # y = s1 * x
  22. L2 = np.array([
  23. # a b c
  24. [0, 0, 0], # 1
  25. [0, 1, 0], # x
  26. [0, 0, 0], # out
  27. [1, 0, 0], # s1
  28. [0, 0, 1], # y
  29. [0, 0, 0] # s2
  30. ])
  31. # s2 = y + x
  32. L3 = np.array([
  33. # a b c
  34. [0, 1, 0], # 1
  35. [1, 0, 0], # x
  36. [0, 0, 0], # out
  37. [0, 0, 0], # s1
  38. [1, 0, 0], # y
  39. [0, 0, 1] # s2
  40. ])
  41. # out = s2 + 5
  42. L4 = np.array([
  43. # a b c
  44. [5, 1, 0], # 1
  45. [0, 0, 0], # x
  46. [0, 0, 1], # out
  47. [0, 0, 0], # s1
  48. [0, 0, 0], # y
  49. [1, 0, 0] # s2
  50. ])
  51. a = np.array([L.transpose()[0] for L in (L1, L2, L3, L4)])
  52. b = np.array([L.transpose()[1] for L in (L1, L2, L3, L4)])
  53. c = np.array([L.transpose()[2] for L in (L1, L2, L3, L4)])
  54. print("A")
  55. print(a)
  56. print("B")
  57. print(b)
  58. print("C")
  59. print(c)
  60. # The witness
  61. s = np.array([
  62. 1,
  63. 3,
  64. 35,
  65. 9,
  66. 27,
  67. 30
  68. ])
  69. print()
  70. #print(s * a * s * b - s * c)
  71. for a_i, b_i, c_i in zip(a, b, c):
  72. assert sum(s * a_i) * sum(s * b_i) - sum(s * c_i) == 0
  73. print("R1CS done.")
  74. print()
  75. def factorial(x):
  76. r = 1
  77. for x_i in range(2, x + 1):
  78. r *= x_i
  79. return r
  80. def combinations(n, r):
  81. return factorial(n) / (factorial(n - r) * factorial(r))
  82. def lagrange(points):
  83. result = np.poly1d([0])
  84. for i, (x_i, y_i) in enumerate(points):
  85. poly = np.poly1d([y_i])
  86. for j, (x_j, y_j) in enumerate(points):
  87. if i == j:
  88. continue
  89. poly *= np.poly1d([1, -x_j]) / (x_i - x_j)
  90. #print(poly)
  91. #print(poly(1), poly(2), poly(3))
  92. result += poly
  93. return result
  94. # 1.5, -5.5, 7
  95. #poly = lagrange([(1, 3), (2, 2), (3, 4)])
  96. #print(poly)
  97. def make_qap(a):
  98. a_qap = []
  99. a_polys = []
  100. for a_i in a.transpose():
  101. poly = lagrange(list(enumerate(a_i, start=1)))
  102. coeffs = poly.c.tolist()
  103. if len(coeffs) < 4:
  104. coeffs = [0] * (4 - len(coeffs)) + coeffs
  105. a_qap.append(coeffs)
  106. a_polys.append(poly)
  107. a_qap = np.array(a_qap)
  108. print(a_qap)
  109. return a_polys
  110. print("A")
  111. a_polys = make_qap(a)
  112. print("B")
  113. b_polys = make_qap(b)
  114. print("C")
  115. c_polys = make_qap(c)
  116. def check(polys, x):
  117. results = []
  118. for poly in polys:
  119. results.append(int(poly(x)))
  120. return results
  121. print()
  122. print("A results at x", check(a_polys, 1))
  123. print()
  124. print("B results at x", check(b_polys, 1))
  125. print()
  126. print("C results at x", check(c_polys, 1))
  127. def combine_polys(polys):
  128. r = np.poly1d([0])
  129. for s_i, p_i in zip(s, polys):
  130. r += s_i * p_i
  131. return r
  132. print()
  133. print()
  134. A = combine_polys(a_polys)
  135. print("A =")
  136. print(A)
  137. B = combine_polys(b_polys)
  138. print("B =")
  139. print(B)
  140. C = combine_polys(c_polys)
  141. print("C =")
  142. print(C)
  143. print()
  144. t = A * B - C
  145. print("t =")
  146. print(t)
  147. # 4 statements in our R1CS: L1, L2, L3, L4
  148. divisor_poly = np.poly1d([1])
  149. for x in range(1, 4 + 1):
  150. divisor_poly *= np.poly1d([1, -x])
  151. quot, remainder = np.polydiv(t, divisor_poly)
  152. assert len(remainder.c) == 1
  153. print()
  154. print("Result of QAP:")
  155. print(int(remainder.c[0]))