groth_poly_commit.sage 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  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 create_proof(p, x):
  36. a = np.array(p.coefficients())
  37. x = np.array([x**i for i in range(len(a))])
  38. # Evaluate the polynomial
  39. z = a.dot(x)
  40. assert len(a) == len(x)
  41. # We will now construct a proof
  42. # Commitments
  43. t = Scalar.random_element()
  44. r = Scalar.random_element()
  45. s = Scalar.random_element()
  46. C_z = int(t) * H + int(z) * G
  47. C_x = int(r) * H + dot_product(a, G_vec)
  48. C_y = int(s) * H + dot_product(x, G_vec)
  49. d_x = np.array([Scalar.random_element() for _ in range(len(x))])
  50. d_y = np.array([Scalar.random_element() for _ in range(len(x))])
  51. r_d = Scalar.random_element()
  52. s_d = Scalar.random_element()
  53. A_d = int(r_d) * H + dot_product(d_x, G_vec)
  54. B_d = int(s_d) * H + dot_product(d_y, G_vec)
  55. # (cx + d_x)(cy + d_y) = d_x d_y + c(x d_y + y d_x) + c^2 xy
  56. t_0 = Scalar.random_element()
  57. t_1 = Scalar.random_element()
  58. C_0 = int(t_0) * H + int(d_x.dot(d_y)) * G
  59. C_1 = int(t_1) * H + int(a.dot(d_y) + x.dot(d_x)) * G
  60. # Challenge
  61. # Using the Fiat-Shamir transform, we would hash the transcript
  62. #c = Scalar.random_element()
  63. c = 110
  64. # Responses
  65. f_x = c * a + d_x
  66. f_y = c * x + d_y
  67. r_x = c * r + r_d
  68. s_y = c * s + s_d
  69. t_z = c**2 * t + c * t_1 + t_0
  70. # Verify
  71. #B_d = int(s_d) * H + dot_product(d_y, G_vec)
  72. #C_y = int(s) * H + dot_product(x, G_vec)
  73. assert int(c) * C_x + A_d == int(r_x) * H + dot_product(f_x, G_vec)
  74. assert int(c) * C_y + B_d == int(s_y) * H + dot_product(f_y, G_vec)
  75. # Actual inner product check
  76. # Comm(f_x f_y) == e^2 C_z + c Comm(x d_y + y d_x) + Comm(d_x d_y)
  77. assert int(t_z) * H + int(f_x.dot(f_y)) * G == int(c**2) * C_z + int(c) * C_1 + C_0
  78. return PolyProof(
  79. poly_commit=C_x,
  80. poly_blind_commit=A_d,
  81. poly_response=f_x,
  82. poly_blind_respond=r_x,
  83. x_blind_factors=(s_d, d_y, s),
  84. evaluation_commits=(C_0, C_1, C_z),
  85. evaluation_response=t_z,
  86. value=z
  87. )
  88. def verify_proof(proof, x):
  89. C_x = proof.poly_commit
  90. A_d = proof.poly_blind_commit
  91. f_x = proof.poly_response
  92. r_x = proof.poly_blind_respond
  93. (s_d, d_y, s) = proof.x_blind_factors
  94. (C_0, C_1, C_z) = proof.evaluation_commits
  95. t_z = proof.evaluation_response
  96. z = proof.value
  97. x = np.array([x**i for i in range(len(a))])
  98. c = 110
  99. f_y = c * x + d_y
  100. s_y = c * s + s_d
  101. B_d = int(s_d) * H + dot_product(d_y, G_vec)
  102. C_y = int(s) * H + dot_product(x, G_vec)
  103. if int(c) * C_x + A_d != int(r_x) * H + dot_product(f_x, G_vec):
  104. return False
  105. if int(c) * C_y + B_d != int(s_y) * H + dot_product(f_y, G_vec):
  106. return False
  107. # Actual inner product check
  108. # Comm(f_x f_y) == e^2 C_z + c Comm(x d_y + y d_x) + Comm(d_x d_y)
  109. if int(t_z) * H + int(f_x.dot(f_y)) * G != int(c**2) * C_z + int(c) * C_1 + C_0:
  110. return False
  111. return True
  112. R.<x> = LaurentPolynomialRing(Scalar)
  113. a = np.array([
  114. Scalar(110), Scalar(56), Scalar(89), Scalar(6543), Scalar(2)
  115. ])
  116. p = 0
  117. for i, a_i in enumerate(a):
  118. p += a_i * x**i
  119. print(p)
  120. xx = Scalar(77)
  121. proof = create_proof(p, xx)
  122. assert verify_proof(proof, xx)
  123. assert proof.value == p(xx)