poly.sage 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001
  2. K = GF(q)
  3. a = K(0x00)
  4. b = K(0x05)
  5. E = EllipticCurve(K, (a, b))
  6. G = E(0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000000, 0x02)
  7. p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
  8. assert E.order() == p
  9. F = GF(p)
  10. Poly.<X> = F[]
  11. k = 3
  12. n = 2^k
  13. x = F(88)
  14. px = (F(110) + F(56) * X + F(89) * X^2 + F(6543) * X^3
  15. + F(2) * X^4 + F(110) * X^5 + F(44) * X^6 + F(78) * X^7)
  16. assert px.degree() <= n
  17. v = px(x)
  18. base_G = [E.random_element(), E.random_element(), E.random_element(),
  19. E.random_element(), E.random_element(), E.random_element(),
  20. E.random_element(), E.random_element()]
  21. base_H = E.random_element()
  22. base_U = E.random_element()
  23. # Make the initial commitment to px
  24. blind = F.random_element()
  25. P = int(blind) * base_H + sum(int(k) * G for k, G in zip(px, base_G))
  26. # Dot product
  27. def dot(x, y):
  28. result = None
  29. for x_i, y_i in zip(x, y):
  30. if result is None:
  31. result = int(x_i) * y_i
  32. else:
  33. result += int(x_i) * y_i
  34. return result
  35. ## Step 2
  36. # Sample a random polynomial of degree n - 1
  37. s_poly = Poly([F.random_element() for _ in range(n)])
  38. # Polynomial should evaluate to 0 at x
  39. s_poly -= s_poly(x)
  40. assert s_poly(x) == 0
  41. ## Step 3
  42. # Commitment randomness
  43. s_poly_blind = F.random_element()
  44. ## Step 4
  45. s_poly_commitment = (int(s_poly_blind) * base_H
  46. + sum(int(k) * G for k, G in zip(s_poly, base_G)))
  47. ## Step 5
  48. iota = F.random_element()
  49. ## Step 8 (following Halo2 not BCSM20 order)
  50. z = F.random_element()
  51. ## Step 6
  52. final_poly = s_poly * iota + px
  53. ##############################
  54. # This code is not in BCSM20 #
  55. ##############################
  56. final_poly -= final_poly(x)
  57. assert final_poly(x) == 0
  58. ##############################
  59. ## Step 7
  60. blind = s_poly_blind * iota + blind
  61. # Step 8 creation of C' does not happen in Halo2 (see the notes
  62. # from "Comparison to other work")
  63. # Initialize the vectors in step 8
  64. a = list(final_poly)
  65. assert len(a) == n
  66. b = [x^i for i in range(n)]
  67. assert len(b) == len(a)
  68. assert dot(a, b) == final_poly(x)
  69. # Now loop from 3, 2, 1
  70. half_3 = 2^2
  71. assert half_3 * 2 == len(a) == len(b) == len(base_G)
  72. a_lo_4, a_hi_4 = a[:half_3], a[half_3:]
  73. b_lo_4, b_hi_4 = b[:half_3], b[half_3:]
  74. G_lo_4, G_hi_4 = base_G[:half_3], base_G[half_3:]
  75. l_3 = dot(a_hi_4, G_lo_4)
  76. r_3 = dot(a_lo_4, G_hi_4)
  77. value_l_3 = dot(a_hi_4, b_lo_4)
  78. value_r_3 = dot(a_lo_4, b_hi_4)
  79. l_randomness_3 = F.random_element()
  80. r_randomness_3 = F.random_element()
  81. l_3 += (int(value_l_3 * z) * base_U
  82. + int(l_randomness_3) * base_H)
  83. r_3 += (int(value_r_3 * z) * base_U
  84. + int(r_randomness_3) * base_H)
  85. challenge_3 = F.random_element()
  86. a_3 = [a_lo_4_i + challenge_3^-1 * a_hi_4_i
  87. for a_lo_4_i, a_hi_4_i in zip(a_lo_4, a_hi_4)]
  88. b_3 = [b_lo_4_i + challenge_3 * b_hi_4_i
  89. for b_lo_4_i, b_hi_4_i in zip(b_lo_4, b_hi_4)]
  90. G_3 = [G_lo_4_i + int(challenge_3) * G_hi_4_i
  91. for G_lo_4_i, G_hi_4_i in zip(G_lo_4, G_hi_4)]
  92. # Not in the paper
  93. blind += l_randomness_3 * challenge_3^-1
  94. blind += r_randomness_3 * challenge_3
  95. # k = 2
  96. half_2 = 2^1
  97. assert half_2 * 2 == len(a_3) == len(b_3) == len(G_3)
  98. a_lo_3, a_hi_3 = a_3[:half_2], a_3[half_2:]
  99. b_lo_3, b_hi_3 = b_3[:half_2], b_3[half_2:]
  100. G_lo_3, G_hi_3 = G_3[:half_2], G_3[half_2:]
  101. l_2 = dot(a_hi_3, G_lo_3)
  102. r_2 = dot(a_lo_3, G_hi_3)
  103. value_l_2 = dot(a_hi_3, b_lo_3)
  104. value_r_2 = dot(a_lo_3, b_hi_3)
  105. l_randomness_2 = F.random_element()
  106. r_randomness_2 = F.random_element()
  107. l_2 += (int(value_l_2 * z) * base_U
  108. + int(l_randomness_2) * base_H)
  109. r_2 += (int(value_r_2 * z) * base_U
  110. + int(r_randomness_2) * base_H)
  111. challenge_2 = F.random_element()
  112. a_2 = [a_lo_3_i + challenge_2^-1 * a_hi_3_i
  113. for a_lo_3_i, a_hi_3_i in zip(a_lo_3, a_hi_3)]
  114. b_2 = [b_lo_3_i + challenge_2 * b_hi_3_i
  115. for b_lo_3_i, b_hi_3_i in zip(b_lo_3, b_hi_3)]
  116. G_2 = [G_lo_3_i + int(challenge_2) * G_hi_3_i
  117. for G_lo_3_i, G_hi_3_i in zip(G_lo_3, G_hi_3)]
  118. blind += l_randomness_2 * challenge_2^-1
  119. blind += r_randomness_2 * challenge_2
  120. # k = 1
  121. half_1 = 2^0
  122. assert half_1 * 2 == len(a_2) == len(b_2) == len(G_2)
  123. a_lo_2, a_hi_2 = a_2[:half_1], a_2[half_1:]
  124. b_lo_2, b_hi_2 = b_2[:half_1], b_2[half_1:]
  125. G_lo_2, G_hi_2 = G_2[:half_1], G_2[half_1:]
  126. l_1 = dot(a_hi_2, G_lo_2)
  127. r_1 = dot(a_lo_2, G_hi_2)
  128. value_l_1 = dot(a_hi_2, b_lo_2)
  129. value_r_1 = dot(a_lo_2, b_hi_2)
  130. l_randomness_1 = F.random_element()
  131. r_randomness_1 = F.random_element()
  132. l_1 += (int(value_l_1 * z) * base_U
  133. + int(l_randomness_1) * base_H)
  134. r_1 += (int(value_r_1 * z) * base_U
  135. + int(r_randomness_1) * base_H)
  136. challenge_1 = F.random_element()
  137. a_1 = [a_lo_2_i + challenge_1^-1 * a_hi_2_i
  138. for a_lo_2_i, a_hi_2_i in zip(a_lo_2, a_hi_2)]
  139. b_1 = [b_lo_2_i + challenge_1 * b_hi_2_i
  140. for b_lo_2_i, b_hi_2_i in zip(b_lo_2, b_hi_2)]
  141. G_1 = [G_lo_2_i + int(challenge_1) * G_hi_2_i
  142. for G_lo_2_i, G_hi_2_i in zip(G_lo_2, G_hi_2)]
  143. blind += l_randomness_1 * challenge_1^-1
  144. blind += r_randomness_1 * challenge_1
  145. # Finished looping
  146. assert len(a_1) == 1
  147. a = a_1[0]
  148. assert len(G_1) == 1
  149. G = G_1[0]
  150. # Verify
  151. # This is a table of how often the challenges appear in G_1, G_2, ...
  152. # as well as a and b (applies equally)
  153. #
  154. # 12345678
  155. # challenge 3: 00001111
  156. # challenge 2: 00110011
  157. # challenge 1: 01010101
  158. #
  159. s_1 = F(1)
  160. s_2 = challenge_1
  161. s_3 = challenge_2
  162. s_4 = challenge_1 * challenge_2
  163. s_5 = challenge_3
  164. s_6 = challenge_1 * challenge_3
  165. s_7 = challenge_2 * challenge_3
  166. s_8 = challenge_1 * challenge_2 * challenge_3
  167. s = (s_1, s_2, s_3, s_4, s_5, s_6, s_7, s_8)
  168. # Verifier can recompute the final G value by doing this calc
  169. assert G == dot(s, base_G)
  170. assert a == dot([s_i^-1 for s_i in s], list(final_poly))
  171. assert b_1[0] == dot(s, [x^i for i in range(n)])
  172. b = b_1[0]
  173. # Alternatively we have a faster form of calculating b which
  174. # arises naturally from the structure of how it's computed.
  175. #
  176. # b = (1, x, x^2, x^3, x^4, x^5, x^6, x^7)
  177. # i = 3
  178. # b = ( 1 + u3 x^4,
  179. # x (1 + u3 x^4),
  180. # x^2 (1 + u3 x^4),
  181. # x^3 (1 + u3 x^4))
  182. # i = 2
  183. # b = ( 1 + u3 x^4 + u2 x^2 (1 + u3 x^4),
  184. # x (1 + u3 x^4 + u2 x^2 (1 + u3 x^4)))
  185. # = ( (1 + u2 x^2)(1 + u3 x^4),
  186. # x (1 + u2 x^2)(1 + u3 x^4))
  187. # i = 1
  188. # b = (1 + u1 x)(1 + u2 x^2)(1 + u3 x^4)
  189. assert ((1 + challenge_1 * x)
  190. * (1 + challenge_2 * x^2) * (1 + challenge_3 * x^4)) == b
  191. # There are 2 versions of the check below.
  192. # This one is the use_challenges() version
  193. msm = (P - int(v) * base_G[0] + int(iota) * s_poly_commitment
  194. + int(challenge_1^-1) * l_1 + int(challenge_1) * r_1
  195. + int(challenge_2^-1) * l_2 + int(challenge_2) * r_2
  196. + int(challenge_3^-1) * l_3 + int(challenge_3) * r_3)
  197. rhs = int(a) * (G + int(b * z) * base_U) + int(blind) * base_H
  198. assert msm == rhs
  199. # The other version allows the verifier to be a supplied a blinded G value.
  200. # They can substitute this G value into the equaion below, and still verify
  201. # the equation.
  202. # This means construct a valid G value that is used in multiple verifications
  203. # repeatedly.
  204. msm = (P - int(v) * base_G[0] + int(iota) * s_poly_commitment
  205. + int(challenge_1^-1) * l_1 + int(challenge_1) * r_1
  206. + int(challenge_2^-1) * l_2 + int(challenge_2) * r_2
  207. + int(challenge_3^-1) * l_3 + int(challenge_3) * r_3)
  208. rhs = int(a * b * z) * base_U + int(a + blind) * base_H
  209. # compute_g()
  210. # We compute s vector combined challenges.
  211. G = dot(s, base_G)
  212. # H is used for blinding.
  213. G -= base_H
  214. # use_g() version
  215. rhs += int(a) * G
  216. # ... and do the final check
  217. assert msm == rhs