groth_poly_commit.sage 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. import numpy as np
  2. from collections import namedtuple
  3. PolyProof = namedtuple("PolyProof", [
  4. "poly_commit",
  5. "poly_blind_commit",
  6. "poly_response",
  7. "poly_blind_respond",
  8. "x_blind_factors",
  9. "evaluation_commits",
  10. "evaluation_response",
  11. "value"
  12. ])
  13. # Implementation of Groth09 inner product proof
  14. q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001
  15. K = GF(q)
  16. a = K(0x00)
  17. b = K(0x05)
  18. E = EllipticCurve(K, (a, b))
  19. G = E(0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000000, 0x02)
  20. p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
  21. assert E.order() == p
  22. Scalar = GF(p)
  23. # Create some generator points. Normally we would use hash to curve.
  24. # All these points will be generators since the curve is a cyclic group
  25. H = E.random_element()
  26. G_vec = [E.random_element() for _ in range(1000)]
  27. def dot_product(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. def poly_commit(p):
  36. # Sage randomly orders terms. No guarantee about ordering.
  37. #a = np.array(p.coefficients())
  38. a = np.array([p[i] for i in range(p.degree() + 1)])
  39. r = Scalar.random_element()
  40. C_x = int(r) * H + dot_product(a, G_vec)
  41. return (r, C_x)
  42. def create_proof(p, r, x):
  43. a = np.array([p[i] for i in range(p.degree() + 1)])
  44. #a = np.array(p.coefficients())
  45. x = np.array([x**i for i in range(p.degree() + 1)])
  46. # Evaluate the polynomial
  47. z = a.dot(x)
  48. assert len(a) == len(x)
  49. # We will now construct a proof
  50. # Commitments
  51. t = Scalar.random_element()
  52. #r = Scalar.random_element()
  53. s = Scalar.random_element()
  54. C_z = int(t) * H + int(z) * G
  55. C_x = int(r) * H + dot_product(a, G_vec)
  56. C_y = int(s) * H + dot_product(x, G_vec)
  57. d_x = np.array([Scalar.random_element() for _ in range(len(x))])
  58. d_y = np.array([Scalar.random_element() for _ in range(len(x))])
  59. r_d = Scalar.random_element()
  60. s_d = Scalar.random_element()
  61. A_d = int(r_d) * H + dot_product(d_x, G_vec)
  62. B_d = int(s_d) * H + dot_product(d_y, G_vec)
  63. # (cx + d_x)(cy + d_y) = d_x d_y + c(x d_y + y d_x) + c^2 xy
  64. t_0 = Scalar.random_element()
  65. t_1 = Scalar.random_element()
  66. C_0 = int(t_0) * H + int(d_x.dot(d_y)) * G
  67. C_1 = int(t_1) * H + int(a.dot(d_y) + x.dot(d_x)) * G
  68. # Challenge
  69. # Using the Fiat-Shamir transform, we would hash the transcript
  70. #c = Scalar.random_element()
  71. c = 110
  72. # Responses
  73. f_x = c * a + d_x
  74. f_y = c * x + d_y
  75. r_x = c * r + r_d
  76. s_y = c * s + s_d
  77. t_z = c**2 * t + c * t_1 + t_0
  78. # Verify
  79. #B_d = int(s_d) * H + dot_product(d_y, G_vec)
  80. #C_y = int(s) * H + dot_product(x, G_vec)
  81. assert int(c) * C_x + A_d == int(r_x) * H + dot_product(f_x, G_vec)
  82. assert int(c) * C_y + B_d == int(s_y) * H + dot_product(f_y, G_vec)
  83. # Actual inner product check
  84. # Comm(f_x f_y) == e^2 C_z + c Comm(x d_y + y d_x) + Comm(d_x d_y)
  85. assert int(t_z) * H + int(f_x.dot(f_y)) * G == int(c**2) * C_z + int(c) * C_1 + C_0
  86. return PolyProof(
  87. poly_commit=C_x,
  88. poly_blind_commit=A_d,
  89. poly_response=f_x,
  90. poly_blind_respond=r_x,
  91. x_blind_factors=(s_d, d_y, s),
  92. evaluation_commits=(C_0, C_1, C_z),
  93. evaluation_response=t_z,
  94. value=z
  95. )
  96. def verify_proof(proof, x):
  97. C_x = proof.poly_commit
  98. A_d = proof.poly_blind_commit
  99. f_x = proof.poly_response
  100. r_x = proof.poly_blind_respond
  101. (s_d, d_y, s) = proof.x_blind_factors
  102. (C_0, C_1, C_z) = proof.evaluation_commits
  103. t_z = proof.evaluation_response
  104. z = proof.value
  105. x = np.array([x**i for i in range(len(a))])
  106. c = 110
  107. f_y = c * x + d_y
  108. s_y = c * s + s_d
  109. B_d = int(s_d) * H + dot_product(d_y, G_vec)
  110. C_y = int(s) * H + dot_product(x, G_vec)
  111. if int(c) * C_x + A_d != int(r_x) * H + dot_product(f_x, G_vec):
  112. return False
  113. if int(c) * C_y + B_d != int(s_y) * H + dot_product(f_y, G_vec):
  114. return False
  115. # Actual inner product check
  116. # Comm(f_x f_y) == e^2 C_z + c Comm(x d_y + y d_x) + Comm(d_x d_y)
  117. if int(t_z) * H + int(f_x.dot(f_y)) * G != int(c**2) * C_z + int(c) * C_1 + C_0:
  118. return False
  119. return True
  120. R.<x> = LaurentPolynomialRing(Scalar)
  121. a = np.array([
  122. Scalar(110), Scalar(56), Scalar(89), Scalar(6543), Scalar(2)
  123. ])
  124. p = 0
  125. for i, a_i in enumerate(a):
  126. p += a_i * x**i
  127. print(p)
  128. xx = Scalar(77)
  129. r, commit = poly_commit(p)
  130. proof = create_proof(p, r, xx)
  131. assert verify_proof(proof, xx)
  132. assert proof.poly_commit == commit
  133. assert proof.value == p(xx)