4.5.2-multi-operation-polynomials.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. from bls_py import bls12381
  2. from bls_py import pairing
  3. from bls_py import ec
  4. from bls_py.fields import Fq, Fq2, Fq6, Fq12, bls12381_q as Q
  5. from finite_fields.modp import IntegersModP
  6. from finite_fields.polynomial import polynomialsOver
  7. import random
  8. n = bls12381.n
  9. g1 = ec.generator_Fq(bls12381)
  10. g2 = ec.generator_Fq2(bls12381)
  11. null = ec.AffinePoint(Fq(n, 0), Fq(n, 1), True, bls12381)
  12. assert null + g1 == g1
  13. null2 = ec.AffinePoint(Fq2.zero(n), Fq2.zero(n), True, bls12381)
  14. assert null2 + g2 == g2
  15. mod_field = IntegersModP(n)
  16. poly = polynomialsOver(mod_field).factory
  17. def lagrange(points):
  18. result = poly([0])
  19. for i, (x_i, y_i) in enumerate(points):
  20. p = poly([y_i])
  21. for j, (x_j, y_j) in enumerate(points):
  22. if i == j:
  23. continue
  24. p *= poly([-x_j, 1]) / (x_i - x_j)
  25. #print(poly)
  26. #print(poly(1), poly(2), poly(3))
  27. result += p
  28. return result
  29. def poly_call(poly, x):
  30. result = mod_field(0)
  31. for degree, coeff in enumerate(poly):
  32. result += coeff * (x**degree)
  33. return result.n
  34. left_points = [
  35. (1, 2), (2, 2), (3, 6)
  36. ]
  37. left_poly = lagrange(left_points)
  38. #l = poly([2]) * poly([1, -1])
  39. print("Left:")
  40. print(left_poly)
  41. for x, y in left_points:
  42. assert poly_call(left_poly, x) == y
  43. right_points = [
  44. (1, 1), (2, 3), (3, 2)
  45. ]
  46. right_poly = lagrange(right_points)
  47. print("Right:")
  48. print(right_poly)
  49. for x, y in right_points:
  50. assert poly_call(right_poly, x) == y
  51. out_points = [
  52. (1, 2), (2, 6), (3, 12)
  53. ]
  54. out_poly = lagrange(out_points)
  55. print("Out:")
  56. print(out_poly)
  57. for x, y in out_points:
  58. assert poly_call(out_poly, x) == y
  59. target_poly = poly([-1, 1]) * poly([-2, 1]) * poly([-3, 1])
  60. assert poly_call(target_poly, 1) == 0
  61. assert poly_call(target_poly, 2) == 0
  62. assert poly_call(target_poly, 3) == 0
  63. main_poly = left_poly * right_poly - out_poly
  64. cofactor_poly = main_poly / target_poly
  65. assert left_poly * right_poly - out_poly == target_poly * cofactor_poly
  66. def rand_scalar():
  67. return random.randrange(1, bls12381.q)
  68. #################################
  69. # Verifier (trusted setup)
  70. #################################
  71. # samples a random value (a secret)
  72. toxic_scalar = rand_scalar()
  73. # calculate the shift
  74. alpha_shift = rand_scalar()
  75. # calculates encryptions of s for all powers i in 0 to d
  76. # E(s^i) = g^s^i
  77. degree = 10
  78. enc_s1 = [
  79. g1 * (toxic_scalar**i) for i in range(degree)
  80. ]
  81. enc_s2 = [
  82. g2 * (toxic_scalar**i) for i in range(degree)
  83. ]
  84. enc_s1_shift = [
  85. g1 * (alpha_shift * toxic_scalar**i) for i in range(degree)
  86. ]
  87. enc_s2_shift = [
  88. g2 * (alpha_shift * toxic_scalar**i) for i in range(degree)
  89. ]
  90. # evaluates unencrypted target polynomial with s: t(s)
  91. toxic_target = (toxic_scalar - 1) * (toxic_scalar - 2) * (toxic_scalar - 3)
  92. # CRS = common reference string = trusted setup parameters
  93. target_crs = g1 * toxic_target
  94. alpha_crs = g2 * alpha_shift
  95. alpha_crs_g1 = g1 * alpha_shift
  96. # Proving key = (encrypted_powers, encrypted_shifted_powers)
  97. # Verify key = (target_crs, alpha_crs)
  98. # encrypted values of s provided to the prover
  99. # Actual values of s are toxic waste and discarded
  100. #################################
  101. # Prover
  102. #################################
  103. # Using encrypted powers and coefficients, evaluates
  104. # E(p(s)) and E(h(s))
  105. def evaluate(poly, encrypted_powers, identity):
  106. result = identity
  107. for power, coeff in zip(encrypted_powers, poly):
  108. result += power * coeff.n
  109. return result
  110. enc_left = evaluate(left_poly, enc_s1, null)
  111. enc_right = evaluate(right_poly, enc_s2, null2)
  112. enc_out = evaluate(out_poly, enc_s1, null)
  113. enc_cofactor = evaluate(cofactor_poly, enc_s2, null2)
  114. # Alpha shifted powers
  115. enc_left_shift = evaluate(left_poly, enc_s1_shift, null)
  116. enc_right_shift = evaluate(right_poly, enc_s2_shift, null2)
  117. enc_out_shift = evaluate(out_poly, enc_s1_shift, null)
  118. #################################
  119. # Verifier
  120. #################################
  121. def restrict_polynomial_g1(encrypted_shift_poly, encrypted_poly):
  122. res1 = pairing.ate_pairing(encrypted_shift_poly, g2)
  123. res2 = pairing.ate_pairing(encrypted_poly, alpha_crs)
  124. assert res1 == res2
  125. def restrict_polynomial_g2(encrypted_shift_poly, encrypted_poly):
  126. res1 = pairing.ate_pairing(g1, encrypted_shift_poly)
  127. res2 = pairing.ate_pairing(alpha_crs_g1, encrypted_poly)
  128. assert res1 == res2
  129. restrict_polynomial_g1(enc_left_shift, enc_left)
  130. restrict_polynomial_g2(enc_right_shift, enc_right)
  131. restrict_polynomial_g1(enc_out_shift, enc_out)
  132. # Valid operation check
  133. # e(g^l, g^r) == e(g^t, g^h) * e(g^o, g)
  134. res1 = pairing.ate_pairing(enc_left, enc_right)
  135. res2 = pairing.ate_pairing(target_crs, enc_cofactor) * \
  136. pairing.ate_pairing(enc_out, g2)
  137. assert res1 == res2