3.5-zero-knowledge.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  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.5 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 (trusted setup)
  18. #################################
  19. # samples a random value (a secret)
  20. s = rand_scalar()
  21. # calculate the shift
  22. a = rand_scalar()
  23. # calculates encryptions of s for all powers i in 0 to d
  24. # E(s^i) = g^s^i
  25. d = 10
  26. encrypted_powers = [
  27. g1 * (s**i) for i in range(d)
  28. ]
  29. encrypted_shifted_powers = [
  30. g1 * (a * s**i) for i in range(d)
  31. ]
  32. # evaluates unencrypted target polynomial with s: t(s)
  33. target = (s - 1) * (s - 2)
  34. # encrypted values of s provided to the prover
  35. # Actual values of s are toxic waste and discarded
  36. #################################
  37. # Prover
  38. #################################
  39. # delta shift
  40. delta = rand_scalar()
  41. # E(p(s)) = p(s)G
  42. # = c_d s^d G + ... + c_1 s^1 G + c_0 s^0 G
  43. # = s^3 G - 3 s^2 G + 2 s G
  44. # E(h(s)) = sG
  45. # t(s) = s^2 - 3s + 2
  46. # E(h(s)) t(s) = s^3 G - 3 s^2 G + 2 s G
  47. # Lets test these manually:
  48. e_s = encrypted_powers
  49. e_p_s = e_s[3] - 3 * e_s[2] + 2 * e_s[1]
  50. e_h_s = e_s[1]
  51. t_s = s**2 - 3*s + 2
  52. # exponentiate with delta
  53. e_p_s *= delta
  54. e_h_s *= delta
  55. assert t_s == target
  56. assert e_p_s == e_h_s * t_s
  57. e_as = encrypted_shifted_powers
  58. e_p_as = e_as[3] - 3 * e_as[2] + 2 * e_as[1]
  59. # exponentiate with delta
  60. e_p_as *= delta
  61. assert e_p_s * a == e_p_as
  62. #############################
  63. # x^3 - 3x^2 + 2x
  64. main_poly = np.poly1d([1, -3, 2, 0])
  65. # (x - 1)(x - 2)
  66. target_poly = np.poly1d([1, -1]) * np.poly1d([1, -2])
  67. # Calculates polynomial h(x) = p(x) / t(x)
  68. cofactor, remainder = main_poly / target_poly
  69. assert remainder == np.poly1d([0])
  70. # Using encrypted powers and coefficients, evaluates
  71. # E(p(s)) and E(h(s))
  72. def evaluate(poly, encrypted_powers):
  73. coeffs = list(poly.coef)[::-1]
  74. result = null
  75. for power, coeff in zip(encrypted_powers, coeffs):
  76. #print(coeff, power)
  77. coeff = int(coeff)
  78. # I have to do this for some strange reason
  79. # Because if coeff is negative and I do += power * coeff
  80. # then it gives me a different result than what I expect
  81. if coeff < 0:
  82. result -= power * (-coeff)
  83. else:
  84. result += power * coeff
  85. # Add delta to the result
  86. # Free extra obfuscation to the polynomial
  87. return result * delta
  88. encrypted_poly = evaluate(main_poly, encrypted_powers)
  89. assert encrypted_poly == e_p_s
  90. encrypted_cofactor = evaluate(cofactor, encrypted_powers)
  91. # Alpha shifted powers
  92. encrypted_shift_poly = evaluate(main_poly, encrypted_shifted_powers)
  93. # resulting g^p and g^h are provided to the verifier
  94. #################################
  95. # Verifier
  96. #################################
  97. # Last check that p = t(s) h
  98. assert encrypted_poly == encrypted_cofactor * target
  99. # Verify (g^p)^a == g^p'
  100. assert encrypted_poly * a == encrypted_shift_poly