4.4-proof-of-operation.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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. import random
  6. import numpy as np
  7. # Section 3.6 from "Why and How zk-SNARK Works"
  8. def rand_scalar():
  9. return random.randrange(1, bls12381.q)
  10. #x = rand_scalar()
  11. #y = ec.y_for_x(x)
  12. g1 = ec.generator_Fq(bls12381)
  13. g2 = ec.generator_Fq2(bls12381)
  14. null = ec.AffinePoint(Fq(Q, 0), Fq(Q, 1), True, bls12381)
  15. assert g1 + null == g1
  16. null2 = ec.AffinePoint(Fq2.zero(Q), Fq2.zero(Q), True, bls12381)
  17. assert null2 + g2 == g2
  18. #################################
  19. # Verifier (trusted setup)
  20. #################################
  21. # samples a random value (a secret)
  22. s = rand_scalar()
  23. # calculate the shift
  24. a = rand_scalar()
  25. # calculates encryptions of s for all powers i in 0 to d
  26. # E(s^i) = g^s^i
  27. d = 10
  28. encrypted_powers = [
  29. g1 * (s**i) for i in range(d)
  30. ]
  31. encrypted_powers_g2 = [
  32. g2 * (s**i) for i in range(d)
  33. ]
  34. encrypted_shifted_powers = [
  35. g1 * (a * s**i) for i in range(d)
  36. ]
  37. encrypted_shifted_powers_g2 = [
  38. g2 * (a * s**i) for i in range(d)
  39. ]
  40. # evaluates unencrypted target polynomial with s: t(s)
  41. target = (s - 1)
  42. # CRS = common reference string = trusted setup parameters
  43. target_crs = g1 * target
  44. alpha_crs = g2 * a
  45. alpha_crs_g1 = g1 * a
  46. # Proving key = (encrypted_powers, encrypted_shifted_powers)
  47. # Verify key = (target_crs, alpha_crs)
  48. # encrypted values of s provided to the prover
  49. # Actual values of s are toxic waste and discarded
  50. #################################
  51. # Prover
  52. #################################
  53. left_poly = np.poly1d([3])
  54. right_poly = np.poly1d([2])
  55. out_poly = np.poly1d([6])
  56. # x^3 - 3x^2 + 2x
  57. main_poly = left_poly * right_poly - out_poly
  58. # (x - 1)
  59. target_poly = np.poly1d([1, -1])
  60. # Calculates polynomial h(x) = p(x) / t(x)
  61. cofactor, remainder = main_poly / target_poly
  62. assert remainder == np.poly1d([0])
  63. # Using encrypted powers and coefficients, evaluates
  64. # E(p(s)) and E(h(s))
  65. def evaluate(poly, encrypted_powers, identity):
  66. coeffs = list(poly.coef)[::-1]
  67. result = identity
  68. for power, coeff in zip(encrypted_powers, coeffs):
  69. #print(coeff, power)
  70. coeff = int(coeff)
  71. # I have to do this for some strange reason
  72. # Because if coeff is negative and I do += power * coeff
  73. # then it gives me a different result than what I expect
  74. if coeff < 0:
  75. result -= power * (-coeff)
  76. else:
  77. result += power * coeff
  78. return result
  79. assert left_poly * right_poly == out_poly
  80. encrypted_left_poly = evaluate(left_poly, encrypted_powers, null)
  81. encrypted_right_poly = evaluate(right_poly, encrypted_powers_g2, null2)
  82. encrypted_out_poly = evaluate(out_poly, encrypted_powers, null)
  83. #assert encrypted_poly == e_p_s
  84. encrypted_cofactor = evaluate(cofactor, encrypted_powers_g2, null2)
  85. # Alpha shifted powers
  86. encrypted_shift_left_poly = evaluate(left_poly, encrypted_shifted_powers, null)
  87. encrypted_shift_right_poly = evaluate(right_poly, encrypted_shifted_powers_g2, null2)
  88. encrypted_shift_out_poly = evaluate(out_poly, encrypted_shifted_powers, null)
  89. # resulting g^p and g^h are provided to the verifier
  90. # proof = (encrypted_poly, encrypted_cofactor, encrypted_shift_poly)
  91. #################################
  92. # Verifier
  93. #################################
  94. # Last check that p = t(s) h
  95. assert pairing.ate_pairing(2 * g1, g2) == pairing.ate_pairing(g1, g2) * pairing.ate_pairing(g1, g2)
  96. # Verify (g^p)^a == g^p'
  97. # Check polynomial restriction:
  98. def check_polynomial_restriction(encrypted_shift_poly, encrypted_poly):
  99. res1 = pairing.ate_pairing(encrypted_shift_poly, g2)
  100. res2 = pairing.ate_pairing(encrypted_poly, alpha_crs)
  101. assert res1 == res2
  102. def check_polynomial_restriction_swapped(encrypted_shift_poly, encrypted_poly):
  103. res1 = pairing.ate_pairing(g1, encrypted_shift_poly)
  104. res2 = pairing.ate_pairing(alpha_crs_g1, encrypted_poly)
  105. assert res1 == res2
  106. check_polynomial_restriction(encrypted_shift_left_poly, encrypted_left_poly)
  107. check_polynomial_restriction_swapped(encrypted_shift_right_poly, encrypted_right_poly)
  108. check_polynomial_restriction(encrypted_shift_out_poly, encrypted_out_poly)
  109. # Valid operation check
  110. # e(g^l, g^r) == e(g^t, g^h) * e(g^o, g)
  111. res1 = pairing.ate_pairing(encrypted_left_poly, encrypted_right_poly)
  112. res2 = pairing.ate_pairing(target_crs, encrypted_cofactor) * \
  113. pairing.ate_pairing(encrypted_out_poly, g2)
  114. assert res1 == res2