halo2.sage 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. import numpy as np
  2. q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001
  3. K = GF(q)
  4. P.<X> = K[]
  5. # GENERATOR^{2^s} where t * 2^s + 1 = q with t odd.
  6. # In other words, this is a t root of unity.
  7. generator = K(5)
  8. # There is a large 2^32 order subgroup in this curve because it is 2-adic
  9. t = (K(q) - 1) / 2^32
  10. assert int(t) % 2 != 0
  11. delta = generator^(2^32)
  12. assert delta^t == 1
  13. # The size of the multiplicative group is phi(q) = q - 1
  14. # And inside this group are 2 distinct subgroups of size t and 2^s.
  15. # delta is the generator for the size t subgroup, and omega for the 2^s one.
  16. # Taking powers of these generators and multiplying them will produce
  17. # unique cosets that divide the entire group for q.
  18. def get_omega():
  19. generator = K(5)
  20. assert (q - 1) % 2^32 == 0
  21. # Root of unity
  22. t = (q - 1) / 2^32
  23. omega = generator**t
  24. assert omega != 1
  25. assert omega^(2^16) != 1
  26. assert omega^(2^31) != 1
  27. assert omega^(2^32) == 1
  28. return omega
  29. # Order of this element is 2^32
  30. omega = get_omega()
  31. k = 4
  32. n = 2^k
  33. omega = omega^(2^32 / n)
  34. assert omega^n == 1
  35. # def foo(s, x, y):
  36. # if s:
  37. # return x * y
  38. # else:
  39. # return x + y
  40. # z = foo(s, x, y)
  41. # Arithmetization for:
  42. # sxy + (s - 1)(x + y) - z = 0
  43. # s(s - 1) = 0
  44. # F1(A1 - 1) + F2 (A1 - I) + F3((1 - A1)(A2 + A3) - A4) + F4(A1 A2 A3 - A4) = 0
  45. A = []
  46. F = []
  47. var_zero = K(0)
  48. var_x = K(4)
  49. var_y = K(6)
  50. var_s = K(1)
  51. var_sxy = var_s * var_x * var_y
  52. var_1s_xy = (1 - var_s) * (var_x + var_y)
  53. # Public
  54. var_z = var_sxy + var_1s_xy
  55. # 4 advice columns
  56. # 4 fixed columns
  57. # 1 instance column
  58. # Row 1
  59. # z = public z
  60. A_1_1, A_2_1, A_3_1, A_4_1 = var_z, 0, 0, 0
  61. F_1_1, F_2_1, F_3_1, F_4_1 = 1, 0, 0, 0
  62. I_1 = var_z
  63. # Row 2
  64. # ~0 == 0
  65. A_1_2, A_2_2, A_3_2, A_4_2 = var_zero, 0, 0, 0
  66. F_1_2, F_2_2, F_3_2, F_4_2 = 0, 1, 0, 0
  67. I_2 = 0
  68. # Row 3
  69. # Boolean check
  70. # (1 - s)(s + 0) == 0
  71. A_1_3, A_2_3, A_3_3, A_4_3 = var_s, var_s, var_zero, var_zero
  72. F_1_3, F_2_3, F_3_3, F_4_3 = 0, 0, 1, 0
  73. I_3 = 0
  74. # Row 4
  75. # s x y == sxy
  76. A_1_4, A_2_4, A_3_4, A_4_4 = var_s, var_x, var_y, var_sxy
  77. F_1_4, F_2_4, F_3_4, F_4_4 = 0, 0, 0, 1
  78. I_4 = 0
  79. # Row 5
  80. # (1 - s)(x + y) = (1-s)(x+y)
  81. A_1_5, A_2_5, A_3_5, A_4_5 = var_s, var_x, var_y, var_1s_xy
  82. F_1_5, F_2_5, F_3_5, F_4_5 = 0, 0, 1, 0
  83. I_5 = 0
  84. # Row 6
  85. # (1 - 0)(sxy + (1-s)(x+y)) = z
  86. A_1_6, A_2_6, A_3_6, A_4_6 = var_zero, var_sxy, var_1s_xy, var_z
  87. F_1_6, F_2_6, F_3_6, F_4_6 = 0, 0, 1, 0
  88. I_6 = 0
  89. A1 = [A_1_1, A_1_2, A_1_3, A_1_4, A_1_5, A_1_6]
  90. A2 = [A_2_1, A_2_2, A_2_3, A_2_4, A_2_5, A_2_6]
  91. A3 = [A_3_1, A_3_2, A_3_3, A_3_4, A_3_5, A_3_6]
  92. A4 = [A_4_1, A_4_2, A_4_3, A_4_4, A_4_5, A_4_6]
  93. F1 = [F_1_1, F_1_2, F_1_3, F_1_4, F_1_5, F_1_6]
  94. F2 = [F_2_1, F_2_2, F_2_3, F_2_4, F_2_5, F_2_6]
  95. F3 = [F_3_1, F_3_2, F_3_3, F_3_4, F_3_5, F_3_6]
  96. F4 = [F_4_1, F_4_2, F_4_3, F_4_4, F_4_5, F_4_6]
  97. I = [I_1, I_2, I_3, I_4, I_5, I_6]
  98. # There should be 5 unused blinding rows.
  99. # see src/plonk/circuit.rs: fn blinding_factors(&self) -> usize;
  100. # We have 9 so we are perfectly fine.
  101. # Add 9 empty rows
  102. assert n - len(A1) == 10
  103. for i in range(10):
  104. A1.append(K.random_element())
  105. A2.append(K.random_element())
  106. A3.append(K.random_element())
  107. A4.append(K.random_element())
  108. F1.append(0)
  109. F2.append(0)
  110. F3.append(0)
  111. F4.append(0)
  112. I.append(K.random_element())
  113. assert (len(A1) == len(A2) == len(A3) == len(A4) == len(F1) == len(F2)
  114. == len(F3) == len(F4) == len(I) == n)
  115. for A_1_i, A_2_i, A_3_i, A_4_i, F_1_i, F_2_i, F_3_i, F_4_i, I_i in zip(
  116. A1, A2, A3, A4, F1, F2, F3, F4, I):
  117. assert (F_1_i * (A_1_i - I_i)
  118. + F_2_i * A_1_i
  119. + F_3_i * ((1 - A_1_i) * (A_2_i + A_3_i) - A_4_i)
  120. + F_4_i * (A_1_i * A_2_i * A_3_i - A_4_i)) == 0
  121. a_1_X = P.lagrange_polynomial((omega^i, A_1_i) for i, A_1_i in enumerate(A1))
  122. a_2_X = P.lagrange_polynomial((omega^i, A_2_i) for i, A_2_i in enumerate(A2))
  123. a_3_X = P.lagrange_polynomial((omega^i, A_3_i) for i, A_3_i in enumerate(A3))
  124. a_4_X = P.lagrange_polynomial((omega^i, A_4_i) for i, A_4_i in enumerate(A4))
  125. f_1_X = P.lagrange_polynomial((omega^i, F_1_i) for i, F_1_i in enumerate(F1))
  126. f_2_X = P.lagrange_polynomial((omega^i, F_2_i) for i, F_2_i in enumerate(F2))
  127. f_3_X = P.lagrange_polynomial((omega^i, F_3_i) for i, F_3_i in enumerate(F3))
  128. f_4_X = P.lagrange_polynomial((omega^i, F_4_i) for i, F_4_i in enumerate(F4))
  129. # Treat the instance wire as a 5th advice wire
  130. a_5_X = P.lagrange_polynomial((omega^i, A_5_i) for i, A_5_i in enumerate(I))
  131. for i, (A_1_i, A_2_i, A_3_i, A_4_i, F_1_i, F_2_i, F_3_i, F_4_i, I_i) in \
  132. enumerate(zip(A1, A2, A3, A4, F1, F2, F3, F4, I)):
  133. assert a_1_X(omega^i) == A_1_i
  134. assert a_2_X(omega^i) == A_2_i
  135. assert a_3_X(omega^i) == A_3_i
  136. assert a_4_X(omega^i) == A_4_i
  137. assert a_5_X(omega^i) == I_i
  138. assert f_1_X(omega^i) == F_1_i
  139. assert f_2_X(omega^i) == F_2_i
  140. assert f_3_X(omega^i) == F_3_i
  141. assert f_4_X(omega^i) == F_4_i
  142. # beta, gamma
  143. beta = K.random_element()
  144. gamma = K.random_element()
  145. # 0 1 2 3 4 5 ... 15
  146. # A1: z, 0, s, s, s, 0,
  147. #
  148. # 16 17 18 19 20 21 ... 31
  149. # A2: -, -, s, x, x, sxy,
  150. #
  151. # 32 33 34 35 36 37 ... 47
  152. # A3: -, -, 0, y, y, (1-s)(x+y),
  153. #
  154. # 48 49 50 51 52 53 ... 63
  155. # A4: -, -, 0, sxy, (1-s)(x + y), z,
  156. #
  157. # 64 65 66 67 68 69 ... 79
  158. # A5: z, -, -, -, -, -,
  159. # z = (0 53 64)
  160. # 0 = (1 5 34 50)
  161. # s = (2 3 4 18)
  162. # x = (19 20)
  163. # sxy = (21 51)
  164. # y = (35 36)
  165. # (1-s)(x+y) = (37 52)
  166. permuted_indices = list(range(n * 5))
  167. assert len(permuted_indices) == 80
  168. # Apply the actual permutation cycles
  169. # z
  170. permuted_indices[0] = 53
  171. permuted_indices[53] = 64
  172. permuted_indices[64] = 0
  173. # ~0
  174. permuted_indices[1] = 5
  175. permuted_indices[5] = 34
  176. permuted_indices[34] = 50
  177. permuted_indices[50] = 1
  178. # s
  179. permuted_indices[2] = 3
  180. permuted_indices[3] = 4
  181. permuted_indices[4] = 18
  182. permuted_indices[18] = 2
  183. # x
  184. permuted_indices[19] = 20
  185. permuted_indices[20] = 19
  186. # sxy
  187. permuted_indices[21] = 51
  188. permuted_indices[51] = 21
  189. # y
  190. permuted_indices[35] = 36
  191. permuted_indices[36] = 35
  192. # (1-s)(x+y)
  193. permuted_indices[37] = 52
  194. permuted_indices[52] = 37
  195. witness = A1 + A2 + A3 + A4 + I
  196. for i, val in enumerate(witness):
  197. assert val == witness[permuted_indices[i]]
  198. # How to join lists together?
  199. indices = ([omega^i for i in range(n)]
  200. + [delta * omega^i for i in range(n)]
  201. + [delta^2 * omega^i for i in range(n)]
  202. + [delta^3 * omega^i for i in range(n)]
  203. + [delta^4 * omega^i for i in range(n)])
  204. assert len(indices) == 80
  205. # Permuted indices
  206. sigma_star = [indices[i] for i in permuted_indices]
  207. s = [sigma_star[:n], sigma_star[n:2 * n], sigma_star[2 * n:3 * n],
  208. sigma_star[3 * n:4 * n], sigma_star[4 * n:]]
  209. assert s[0] + s[1] + s[2] + s[3] + s[4] == sigma_star
  210. v = [A1, A2, A3, A4, I]
  211. # We split the columns into sets of size m.
  212. # Here we will use m = 1 for illustration purposes
  213. # We have 6 usable rows
  214. # n = 16 rows total
  215. # row u (q_last) will be the 7th row
  216. # So we have 9 unusable rows
  217. q_blind = [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]
  218. q_last = [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  219. # Turn both of these into polynomial form
  220. q_blind = P.lagrange_polynomial((omega^i, q_i) for i, q_i in enumerate(q_blind))
  221. assert q_blind(omega^5) == 0
  222. assert q_blind(omega^6) == 0
  223. assert q_blind(omega^7) == 1
  224. assert q_blind(omega^11) == 1
  225. q_last = P.lagrange_polynomial((omega^i, q_i) for i, q_i in enumerate(q_last))
  226. assert q_last(omega^5) == 0
  227. assert q_last(omega^6) == 1
  228. assert q_last(omega^7) == 0
  229. assert q_last(omega^11) == 0
  230. m = 5
  231. assert n == 16
  232. # 6 usable rows
  233. u = 6
  234. # There are 5 columns
  235. # We will split the columns partitions into 5 partitions to make things easy
  236. # So b = 5, and each partition contains only a single column
  237. # We still iterate over the column to make it more obvious
  238. m = 1
  239. permutation_points = [(1, 1)]
  240. last_y_value = 1
  241. ZP = []
  242. # a is the current column partition we are aggregating
  243. for a in range(5):
  244. # j iterates over the rows
  245. for j in range(u):
  246. current = last_y_value
  247. # i iterates over the columns in our partition
  248. for i in range(a * m, (a + 1) * m):
  249. current *= v[i][j] + beta * delta^i * omega^j + gamma
  250. current /= v[i][j] + beta * s[i][j] + gamma
  251. last_y_value = current
  252. permutation_points.append((omega^(j + 1), current))
  253. ZP_a = P.lagrange_polynomial(permutation_points)
  254. ZP.append(ZP_a)
  255. permutation_points = [(1, last_y_value)]
  256. # l_0(X) (1 - ZP,0(X)) = 0
  257. # => ZP,0(1) = 1
  258. assert ZP[0](1) == 1
  259. # Checks for l_0(X) (ZP,a(X) - ZP,a-1(omega^u X)) = 1
  260. # => ZP,a(Z) = ZP,a-1(omega^u X)
  261. # This copies the end value from one partition to the next one
  262. assert ZP[1](omega^0) == ZP[0](omega^u)
  263. assert ZP[2](omega^0) == ZP[1](omega^u)
  264. assert ZP[3](omega^0) == ZP[2](omega^u)
  265. assert ZP[4](omega^0) == ZP[3](omega^u)
  266. # Allow the last value to be either 0 or 1 for full ZK
  267. assert ZP[4](omega^u) in (0, 1)
  268. y = K.random_element()
  269. gate_0 = f_1_X * (a_1_X - a_5_X)
  270. gate_1 = f_2_X * a_1_X
  271. gate_2 = f_3_X * ((1 - a_1_X) * (a_2_X + a_3_X) - a_4_X)
  272. gate_3 = f_4_X * (a_1_X * a_2_X * a_3_X - a_4_X)
  273. c = gate_0 + y * gate_1 + y^2 * gate_2 + y^3 * gate_3
  274. t = X^n - 1
  275. for i in range(n):
  276. assert c(omega^i) == 0
  277. # Normally we do:
  278. #h = c / t
  279. # But for some reason sage is producing fractional coefficients
  280. h, rem = c.quo_rem(t)
  281. assert rem == 0
  282. # We send commitments to the terms of h(X)
  283. # h_0(x), ..., h_{d - 1}(x)
  284. # Commitments:
  285. # H = [H_0, ..., H_{d - 1}]
  286. x = K.random_element()
  287. # Send evaluations at x of everything we committed to so far
  288. # A_0(x), ..., A_{m - 1}(x)
  289. # ZP,0(x), ..., ZP,b-1(x)
  290. # H_0(x), ..., H_{d-1}(x)
  291. a_evals = [a_1_X(x), a_2_X(x), a_3_X(x), a_4_X(x), a_5_X(x)]
  292. h_evals = []
  293. # Iterate starting from lowest powers first
  294. h_test = 0
  295. for i, h_i in enumerate(h):
  296. h_evals.append(h_i * x^i)
  297. h_test += h_i * X^i
  298. assert h_test == h
  299. assert sum(h_evals) == h(x)
  300. assert sum(h_evals) * t(x) == (
  301. f_1_X(x) * (a_evals[0] - a_evals[4])
  302. + y * f_2_X(x) * a_evals[0]
  303. + y^2 * f_3_X(x) * ((1 - a_evals[0]) * (a_evals[1] + a_evals[2])
  304. - a_evals[3])
  305. + y^3 * f_4_X(x) * (a_evals[0] * a_evals[1] * a_evals[2] - a_evals[3]))