bltprf-reduced.sage 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001
  2. K = GF(q)
  3. a = K(0x00)
  4. b = K(0x05)
  5. E = EllipticCurve(K, (a, b))
  6. G = E(0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000000, 0x02)
  7. p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
  8. assert E.order() == p
  9. Scalar = GF(p)
  10. k = 3
  11. n = 2^k
  12. start_a = [Scalar(110), Scalar(56), Scalar(89), Scalar(6543),
  13. Scalar(2), Scalar(110), Scalar(44), Scalar(78)]
  14. x = Scalar.random_element()
  15. start_b = [x^i for i in range(n)]
  16. start_G = [E.random_element(), E.random_element(), E.random_element(),
  17. E.random_element(), E.random_element(), E.random_element(),
  18. E.random_element(), E.random_element()]
  19. assert len(start_a) == len(start_b) == len(start_G) == n
  20. # Dot product
  21. def dot(x, y):
  22. result = None
  23. for x_i, y_i in zip(x, y):
  24. if result is None:
  25. result = int(x_i) * y_i
  26. else:
  27. result += int(x_i) * y_i
  28. return result
  29. # This is the main commitment we are proving over
  30. P = dot(start_a, start_G)
  31. challenges = []
  32. commits = []
  33. a, G = start_a, start_G
  34. # Iterate k times where n = 2^k
  35. for current_k in range(k, 0, -1):
  36. # This should make sense to you
  37. half = 2^(current_k - 1)
  38. assert half * 2 == len(a)
  39. a_lo, a_hi = a[:half], a[half:]
  40. G_lo, G_hi = G[:half], G[half:]
  41. # L = <a_hi, G_lo>
  42. # R = <a_lo, G_hi>
  43. L = dot(a_hi, G_lo)
  44. R = dot(a_lo, G_hi)
  45. #z_L = dot(a[half:], b[:half])
  46. #z_R = dot(a[:half], b[half:])
  47. commits.append((L, R))
  48. # Random x value
  49. challenge = Scalar.random_element()
  50. challenges.append(challenge)
  51. # a = a_lo + x^-1 a_hi
  52. # G = G_lo + x G_hi
  53. a = [a_lo_i + challenge^-1 * a_hi_i
  54. for a_lo_i, a_hi_i in zip(a_lo, a_hi)]
  55. G = [G_lo_i + int(challenge) * G_hi_i
  56. for G_lo_i, G_hi_i in zip(G_lo, G_hi)]
  57. assert len(a) == len(G) == half
  58. # Last iteration
  59. if current_k == 1:
  60. assert len(a) == 1
  61. assert len(G) == 1
  62. final_a = a[0]
  63. final_G = G[0]
  64. assert len(challenges) == k
  65. # G_3 = [G1, G2, G3, G4, G5, G6, G7, G8]
  66. # G_2 = [
  67. # G1 + x G5,
  68. # G2 + x G6,
  69. # G3 + x G7,
  70. # G4 + x G8
  71. # ]
  72. # G_1 = [
  73. # G_2_1 + x G_2_3,
  74. # G_2_2 + x G_2_4
  75. # ] = [
  76. # (G1 + x G5) + x (G3 + x G7) = G1 + x G3 + x G5 + x^2 G7,
  77. # (G2 + x G6) + x (G4 + x G8) = G2 + x G4 + x G6 + x^2 G8
  78. # ]
  79. #
  80. # We end up with a single remaining value
  81. #
  82. # G_0 = G_1_1 + x G_1_2
  83. # = G1 + x G2 + x G3 + x^2 G4 + x G5 + x^2 G6 + x^2 G7 + x^3 G8
  84. def get_jth_bit(value, idx):
  85. digits = bin(value)[2:]
  86. # Add zero padding
  87. digits = digits.zfill(k)
  88. return True if digits[idx] == "1" else False
  89. # get scalar values
  90. counters = []
  91. for i in range(1, n + 1):
  92. s = Scalar(1)
  93. for j in range(0, k):
  94. if get_jth_bit(i - 1, j):
  95. b = 1
  96. else:
  97. b = 0
  98. s *= challenges[j]^b
  99. counters.append(s)
  100. assert len(counters) == len(start_G)
  101. # Verifier can recompute the final G value by doing this calc
  102. G_verif = dot(counters, start_G)
  103. assert G_verif == final_G
  104. # final_a value is passed to the verifier
  105. # We can also get this final G value by just looping like we did
  106. # in the proving algo, and recomputing the G values.
  107. # Verification check
  108. L, R = zip(*commits)
  109. challenges_inv = [c^-1 for c in challenges]
  110. assert int(final_a) * G_verif == (P
  111. + dot(challenges, R) + dot(challenges_inv, L))