crypto.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. import hashlib
  2. import random
  3. def ff_inv(a, p):
  4. a %= p
  5. # extended euclidean algorithm
  6. # ps + at = 1
  7. t = 0
  8. new_t = 1
  9. r = p
  10. new_r = a
  11. while new_r != 0:
  12. quotient = r // new_r
  13. t, new_t = new_t, t - quotient * new_t
  14. r, new_r = new_r, r - quotient * new_r
  15. assert r == 1
  16. if t < 0:
  17. t += p
  18. return t
  19. class EllipticCurve:
  20. def __init__(self, p, A, B, order, G, H):
  21. self.p = p
  22. self.A = A
  23. self.B = B
  24. self.order = order
  25. self.G = G
  26. self.H = H
  27. assert self.is_valid(G)
  28. assert self.is_valid(H)
  29. def is_valid(self, P):
  30. x, y, z = P
  31. if z == 0:
  32. return x != 0 or y != 0
  33. z_inv = ff_inv(z, self.p)
  34. x, y = x * z_inv, y * z_inv
  35. return y**2 % self.p == (x**3 + self.A * x + self.B) % self.p
  36. def add(self, p1, p2):
  37. x1, y1, z1 = p1
  38. x2, y2, z2 = p2
  39. if z1 == 0:
  40. return (x2, y2, z2)
  41. elif z2 == 0:
  42. return (x1, y1, z1)
  43. if x1 == x2:
  44. if y1 != y2:
  45. return (0, 1, 0)
  46. assert y1 != 0
  47. m = (3 * x1**2 + self.A) * ff_inv(2*y1, self.p)
  48. else:
  49. m = (y2 - y1) * ff_inv(x2 - x1, self.p)
  50. x3 = (m**2 - x1 - x2) % self.p
  51. y3 = (m * (x1 - x3) - y1) % self.p
  52. return (x3, y3, 1)
  53. def multiply(self, m, p):
  54. bits = f"{m:b}"
  55. result = (0, 1, 0)
  56. temp = p
  57. for bit in bits[::-1]:
  58. if bit == "1":
  59. result = self.add(result, temp)
  60. temp = self.add(temp, temp)
  61. return result
  62. def random_point(self):
  63. m = self.random_scalar()
  64. return self.multiply(m, self.G)
  65. def random_scalar(self):
  66. m = random.randrange(0, self.order - 1)
  67. return m
  68. def random_base(self):
  69. m = random.randrange(0, self.p - 1)
  70. return m
  71. def pallas_curve():
  72. # Pallas
  73. p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
  74. q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001
  75. G = (5, 5392431450607408583390510508521091931943415030464003135511088002453056875732, 1)
  76. H = (9762257241998025279988087154025308614062019274413483967640476725944341089207,
  77. 12058632856930756995627167820351407063813260358041446014729496773111030695755, 1)
  78. ec = EllipticCurve(p, 0, 5, q, G, H)
  79. A = (144931808354919915876542440378319484704499556634959420306426167479163065488,
  80. 2699682121356767698440748624399854659825391162912545787181017961871465868196, 1)
  81. B = (16017037670495191561606513965775243786961447026019262496667491008912834496943,
  82. 20395164507282344548629891414360366999207473153143014512687861307997120664849, 1)
  83. assert ec.add(A, B) == (2414658659502531855741199170408914396997834981355655923471364687102714431309, 21133344194418979683767005688724798091220515434220043854575260979109407444719, 1)
  84. m = 26322809409216846271933211244226061368157231119725763192402071651286829040466
  85. assert ec.multiply(m, G) == (15862887453366837597569434439063150886012590021428640083047997467990450633825, 25887284719793568129480941070850220101898092026705204234126448799557008384178, 1)
  86. return ec
  87. def pedersen_encrypt(x, y, ec):
  88. vcv = ec.multiply(x, ec.G)
  89. vcr = ec.multiply(y, ec.H)
  90. return ec.add(vcv, vcr)
  91. def ff_hash(p, *args):
  92. hasher = hashlib.sha256()
  93. for arg in args:
  94. match arg:
  95. case int() as arg:
  96. hasher.update(arg.to_bytes(32, byteorder="little"))
  97. case bytes() as arg:
  98. hasher.update(arg)
  99. case _:
  100. raise Exception(f"unknown hash arg '{arg}' type: {type(arg)}")
  101. value = int.from_bytes(hasher.digest(), byteorder="little")
  102. return value % p
  103. def hash_point(point, message=None):
  104. hasher = hashlib.sha256()
  105. for x_i in point:
  106. hasher.update(x_i.to_bytes(32, byteorder="little"))
  107. # Optional message
  108. if message is not None:
  109. hasher.update(message)
  110. value = int.from_bytes(hasher.digest(), byteorder="little")
  111. return value
  112. def sign(message, secret, ec):
  113. ephem_secret = ec.random_scalar()
  114. ephem_public = ec.multiply(ephem_secret, ec.G)
  115. challenge = hash_point(ephem_public, message) % ec.order
  116. response = (ephem_secret + challenge * secret) % ec.order
  117. return ephem_public, response
  118. def verify(message, signature, public, ec):
  119. ephem_public, response = signature
  120. challenge = hash_point(ephem_public, message) % ec.order
  121. # sG
  122. lhs = ec.multiply(response, ec.G)
  123. # R + cP
  124. rhs_cP = ec.multiply(challenge, public)
  125. rhs = ec.add(ephem_public, rhs_cP)
  126. return lhs == rhs