3-encrypted-polynomial.py 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  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.3.4 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. #################################
  17. # Verifier
  18. #################################
  19. # samples a random value (a secret)
  20. s = rand_scalar()
  21. # calculates encryptions of s for all powers i in 0 to d
  22. # E(s^i) = g^s^i
  23. d = 10
  24. encrypted_powers = [
  25. g1 * (s**i) for i in range(d)
  26. ]
  27. # evaluates unencrypted target polynomial with s: t(s)
  28. target = (s - 1) * (s - 2)
  29. # encrypted values of s provided to the prover
  30. #################################
  31. # Prover
  32. #################################
  33. # E(p(s)) = p(s)G
  34. # = c_d s^d G + ... + c_1 s^1 G + c_0 s^0 G
  35. # = s^3 G - 3 s^2 G + 2 s G
  36. # E(h(s)) = sG
  37. # t(s) = s^2 - 3s + 2
  38. # E(h(s)) t(s) = s^3 G - 3 s^2 G + 2 s G
  39. # Lets test these manually:
  40. e_s = encrypted_powers
  41. e_p_s = e_s[3] - 3 * e_s[2] + 2 * e_s[1]
  42. e_h_s = e_s[1]
  43. t_s = s**2 - 3*s + 2
  44. assert t_s == target
  45. assert e_p_s == e_h_s * t_s
  46. #############################
  47. # x^3 - 3x^2 + 2x
  48. main_poly = np.poly1d([1, -3, 2, 0])
  49. # (x - 1)(x - 2)
  50. target_poly = np.poly1d([1, -1]) * np.poly1d([1, -2])
  51. # Calculates polynomial h(x) = p(x) / t(x)
  52. cofactor, remainder = main_poly / target_poly
  53. assert remainder == np.poly1d([0])
  54. # Using encrypted powers and coefficients, evaluates
  55. # E(p(s)) and E(h(s))
  56. def evaluate(poly, encrypted_powers):
  57. coeffs = list(poly.coef)[::-1]
  58. result = null
  59. for power, coeff in zip(encrypted_powers, coeffs):
  60. #print(coeff, power)
  61. coeff = int(coeff)
  62. if coeff < 0:
  63. result -= power * (-coeff)
  64. else:
  65. result += power * coeff
  66. return result
  67. encrypted_poly = evaluate(main_poly, encrypted_powers)
  68. assert encrypted_poly == e_p_s
  69. encrypted_cofactor = evaluate(cofactor, encrypted_powers)
  70. # resulting g^p and g^h are provided to the verifier
  71. #################################
  72. # Verifier
  73. #################################
  74. # Last check that p = t(s) h
  75. assert encrypted_poly == encrypted_cofactor * target