halo1.sage 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. import numpy as np
  2. from groth_poly_commit import Scalar, poly_commit, create_proof, verify_proof
  3. K = Scalar
  4. # Just use the same finite field we put in the polynomial commitment scheme file
  5. #p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
  6. #K = FiniteField(p)
  7. R.<x, y> = LaurentPolynomialRing(K)
  8. var_one = K(1)
  9. var_x = K(4)
  10. var_y = K(6)
  11. var_s = K(1)
  12. var_xy = var_x * var_y
  13. var_sxy = var_s * var_xy
  14. var_1_neg_s = var_one - var_s
  15. var_x_y = var_x + var_y
  16. var_1_neg_s_x_y = var_1_neg_s * var_x_y
  17. var_s_neg_1 = -var_1_neg_s
  18. var_zero = K(0)
  19. public_v = var_s * (var_x * var_y) + (1 - var_s) * (var_x + var_y)
  20. a = np.array([
  21. var_one, var_x, var_xy, var_1_neg_s, var_s
  22. ])
  23. b = np.array([
  24. var_one, var_y, var_s, var_x_y, var_s_neg_1
  25. ])
  26. c = np.array([
  27. var_one, var_xy, var_sxy, var_1_neg_s_x_y, var_zero
  28. ])
  29. assert len(a) == len(b)
  30. assert len(b) == len(c)
  31. for i, (a_i, b_i, c_i) in enumerate(zip(a, b, c), 1):
  32. try:
  33. assert a_i * b_i == c_i
  34. except AssertionError:
  35. print("Error for %i" % i)
  36. raise
  37. # 1 - s = -(s - 1)
  38. u1 = np.array([0, 0, 0, 1, 0])
  39. v1 = np.array([0, 0, 0, 0, 1])
  40. w1 = np.array([0, 0, 0, 0, 0])
  41. k1 = 0
  42. assert a.dot(u1) + b.dot(v1) + c.dot(w1) == k1
  43. # xy = xy
  44. u2 = np.array([0, 0, 1, 0, 0])
  45. v2 = np.array([0, 0, 0, 0, 0])
  46. w2 = np.array([0, -1, 0, 0, 0])
  47. k2 = 0
  48. assert a.dot(u2) + b.dot(v2) + c.dot(w2) == k2
  49. # s = s
  50. u3 = np.array([0, 0, 0, 0, -1])
  51. v3 = np.array([0, 0, 1, 0, 0])
  52. w3 = np.array([0, 0, 0, 0, 0])
  53. k3 = 0
  54. assert a.dot(u3) + b.dot(v3) + c.dot(w3) == k3
  55. # zero = 0
  56. u4 = np.array([0, 0, 0, 0, 0])
  57. v4 = np.array([0, 0, 0, 0, 0])
  58. w4 = np.array([0, 0, 0, 0, 1])
  59. k4 = 0
  60. assert a.dot(u4) + b.dot(v4) + c.dot(w4) == k4
  61. # 1 - s
  62. u5 = np.array([1, 0, 0, -1, 0])
  63. v5 = np.array([0, 0, -1, 0, 0])
  64. w5 = np.array([0, 0, 0, 0, 0])
  65. k5 = 0
  66. assert a.dot(u5) + b.dot(v5) + c.dot(w5) == k5
  67. # x + y
  68. u6 = np.array([0, 1, 0, 0, 0])
  69. v6 = np.array([0, 1, 0, -1, 0])
  70. w6 = np.array([0, 0, 0, 0, 0])
  71. k6 = 0
  72. assert a.dot(u6) + b.dot(v6) + c.dot(w6) == k6
  73. # Final check:
  74. # v = s(xy) + (1 - s)(x + y)
  75. u7 = np.array([0, 0, 0, 0, 0])
  76. v7 = np.array([0, 0, 0, 0, 0])
  77. w7 = np.array([0, 0, 1, 1, 0])
  78. k7 = public_v
  79. assert a.dot(u7) + b.dot(v7) + c.dot(w7) == k7
  80. u = np.vstack((u1, u2, u3, u4, u5, u6, u7))
  81. v = np.vstack((v1, v2, v3, v4, v5, v6, v7))
  82. w = np.vstack((w1, w2, w3, w4, w5, w6, w7))
  83. assert u.shape == v.shape
  84. assert u.shape == w.shape
  85. k = np.array((k1, k2, k3, k4, k5, k6, k7))
  86. p = K(0)
  87. for i, (a_i, b_i, c_i) in enumerate(zip(a, b, c), 1):
  88. #print(a_i, "\t", b_i, "\t", c_i)
  89. p += y**i * (a_i * b_i - c_i)
  90. print(p)
  91. p = K(0)
  92. for q, (u_q, v_q, w_q, k_q) in enumerate(zip(u, v, w, k)):
  93. p += y**q * (a.dot(u_q) + b.dot(v_q) + c.dot(w_q) - k_q)
  94. print(p)
  95. n = len(a)
  96. assert len(b) == n
  97. assert len(c) == n
  98. assert u.shape == (7, n)
  99. assert v.shape == u.shape
  100. assert w.shape == u.shape
  101. assert k.shape == (7,)
  102. r_x_y = 0
  103. s_x_y = 0
  104. for i, (a_i, b_i, c_i) in enumerate(zip(a, b, c), 1):
  105. assert 1 <= i <= n
  106. r_x_y += x**i * y**i * a_i
  107. r_x_y += x**-i * y**-i * b_i
  108. r_x_y += x**(-i - n) * y**(-i - n) * c_i
  109. u_i = u.T[i - 1]
  110. v_i = v.T[i - 1]
  111. w_i = w.T[i - 1]
  112. u_i_Y = 0
  113. v_i_Y = 0
  114. w_i_Y = 0
  115. for q, (u_q_i, v_q_i, w_q_i) in enumerate(zip(u_i, v_i, w_i), 1):
  116. assert 1 <= q <= 7
  117. u_i_Y += y**q * u_q_i
  118. v_i_Y += y**q * v_q_i
  119. w_i_Y += y**q * w_q_i
  120. s_x_y += u_i_Y * x**-i + v_i_Y * x**i + w_i_Y * x**(i + n)
  121. k_y = 0
  122. for q, k_q in enumerate(k, 1):
  123. assert 1 <= q <= 7
  124. k_y += y**q * k_q
  125. # Section 6, Figure 2
  126. #
  127. # zkP1
  128. # 4 blinding factors since we evaluate r(X, Y) 3 times
  129. # Blind r(X, Y)
  130. for i in range(1, 4 + 1):
  131. blind_c_i = K.random_element()
  132. r_x_y += x**(-2*n - i) * y**(-2*n - i) * blind_c_i
  133. # Commit to r(X, Y)
  134. s_prime_x_y = y**n * s_x_y
  135. for i in range(1, n):
  136. s_prime_x_y -= (y**i + y**-i) * x**(i + n)
  137. r_x_1 = r_x_y(y=K(1))
  138. t_x_y = r_x_1 * (r_x_y + s_prime_x_y) - y**n * k_y
  139. # This can be opened to r(X, Y) since r(X, Y) = r(XY, 1)
  140. r_x_1_scaled = (r_x_1 * x**(3*n - 1)).univariate_polynomial()
  141. rx1_commit_blind, rx1_commit = poly_commit(r_x_1_scaled)
  142. print("===================")
  143. print(" t(X, Y)")
  144. print("===================")
  145. power_dict = ["⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹"]
  146. def superscript(number):
  147. sign = ""
  148. if number < 0:
  149. sign = "⁻"
  150. number = -number
  151. return sign + "".join([power_dict[int(digit)] for digit in list(str(number))])
  152. decorated = []
  153. for (x_power, y_power), coeff in t_x_y.dict().items():
  154. if coeff == 1:
  155. coeff = ""
  156. display = "%s X%s Y%s" % (coeff, superscript(x_power), superscript(y_power))
  157. decorated.append([x_power, y_power, display])
  158. decorated.sort(key=lambda x: (x[0], -x[1]))
  159. for _, _, display in decorated:
  160. print(display)
  161. print()
  162. print("Constant coefficient:", t_x_y.constant_coefficient())
  163. print()
  164. # zkV1
  165. # Send a random y
  166. challenge_y = K.random_element()
  167. # zkP2
  168. # Commit to t(X, y)
  169. t_x = t_x_y(y=challenge_y)
  170. t_x = t_x.univariate_polynomial()
  171. print("===================")
  172. print(" t(X, y)")
  173. print("===================")
  174. print(t_x.dict())
  175. print()
  176. print("Constant coefficient:", t_x.constant_coefficient())
  177. # Split the polynomial into low and hi versions
  178. t_lo_x = 0
  179. t_hi_x = 0
  180. smallest_power = -min(t_x.dict().keys())
  181. for power, coeff in t_x.dict().items():
  182. assert power != 0
  183. if power < 0:
  184. t_lo_x += x**(smallest_power + power) * coeff
  185. else:
  186. t_hi_x += x**(power - 1) * coeff
  187. d = t_lo_x.degree() + 1
  188. t_lo_x = t_lo_x.univariate_polynomial()
  189. t_hi_x = t_hi_x.univariate_polynomial()
  190. assert (t_lo_x * x**-d + t_hi_x * x).univariate_polynomial() == t_x
  191. T_lo_commit_blind, T_lo = poly_commit(t_lo_x)
  192. T_hi_commit_blind, T_hi = poly_commit(t_hi_x)
  193. # zkV2
  194. # Send a random z
  195. challenge_z = K.random_element()
  196. # zkP3
  197. # Evaluate a = r(z, 1)
  198. a = r_x_y(x=challenge_z, y=K(1))
  199. # Evaluate b = r(z, y)
  200. b = r_x_y(x=challenge_z, y=challenge_y)
  201. # Evaluate t = t(z, y)
  202. t = t_x_y(x=challenge_z, y=challenge_y)
  203. # Evaluate s = s(z, y)
  204. s = s_prime_x_y(x=challenge_z, y=challenge_y)
  205. # Calculate equivalent openings
  206. # s'(X, Y) is known by both prover and verifier
  207. a_proof = create_proof(r_x_1_scaled, rx1_commit_blind, challenge_z)
  208. assert a_proof.poly_commit == rx1_commit
  209. b_proof = create_proof(r_x_1_scaled, rx1_commit_blind, challenge_y * challenge_z)
  210. assert b_proof.poly_commit == rx1_commit
  211. t_proof_lo = create_proof(t_lo_x, T_lo_commit_blind, challenge_z)
  212. assert t_proof_lo.poly_commit == T_lo
  213. t_proof_hi = create_proof(t_hi_x, T_hi_commit_blind, challenge_z)
  214. assert t_proof_hi.poly_commit == T_hi
  215. # Signature of correct computation not yet implemented
  216. # So just use s for now as is
  217. # Scaling factor
  218. verifier_rescale = challenge_z**(-3*n + 1)
  219. assert a_proof.value * verifier_rescale == a
  220. verifier_rescale = (challenge_y * challenge_z)**(-3*n + 1)
  221. assert b_proof.value * verifier_rescale == b
  222. # zkV3
  223. # Recalculate t from a, b and s
  224. t_new = t_proof_lo.value * challenge_z**-d + t_proof_hi.value * challenge_z
  225. assert t_new == t
  226. t = t_new
  227. k = (y**n * k_y)(y=challenge_y)
  228. t_new = a * (b + s) - k
  229. assert t_new == t
  230. # Verify polynomial commitments