eccref.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. import sys
  2. import numbers
  3. import itertools
  4. assert sys.version_info[:2] >= (3,0), "This is Python 3 code"
  5. from numbertheory import *
  6. class AffinePoint(object):
  7. """Base class for points on an elliptic curve."""
  8. def __init__(self, curve, *args):
  9. self.curve = curve
  10. if len(args) == 0:
  11. self.infinite = True
  12. self.x = self.y = None
  13. else:
  14. assert len(args) == 2
  15. self.infinite = False
  16. self.x = ModP(self.curve.p, args[0])
  17. self.y = ModP(self.curve.p, args[1])
  18. self.check_equation()
  19. def __neg__(self):
  20. if self.infinite:
  21. return self
  22. return type(self)(self.curve, self.x, -self.y)
  23. def __mul__(self, rhs):
  24. if not isinstance(rhs, numbers.Integral):
  25. raise ValueError("Elliptic curve points can only be multiplied by integers")
  26. P = self
  27. if rhs < 0:
  28. rhs = -rhs
  29. P = -P
  30. toret = self.curve.point()
  31. n = 1
  32. nP = P
  33. while rhs != 0:
  34. if rhs & n:
  35. rhs -= n
  36. toret += nP
  37. n += n
  38. nP += nP
  39. return toret
  40. def __rmul__(self, rhs):
  41. return self * rhs
  42. def __sub__(self, rhs):
  43. return self + (-rhs)
  44. def __rsub__(self, rhs):
  45. return (-self) + rhs
  46. def __str__(self):
  47. if self.infinite:
  48. return "inf"
  49. else:
  50. return "({},{})".format(self.x, self.y)
  51. def __repr__(self):
  52. if self.infinite:
  53. args = ""
  54. else:
  55. args = ", {}, {}".format(self.x, self.y)
  56. return "{}.Point({}{})".format(type(self.curve).__name__,
  57. self.curve, args)
  58. def __eq__(self, rhs):
  59. if self.infinite or rhs.infinite:
  60. return self.infinite and rhs.infinite
  61. return (self.x, self.y) == (rhs.x, rhs.y)
  62. def __ne__(self, rhs):
  63. return not (self == rhs)
  64. def __lt__(self, rhs):
  65. raise ValueError("Elliptic curve points have no ordering")
  66. def __le__(self, rhs):
  67. raise ValueError("Elliptic curve points have no ordering")
  68. def __gt__(self, rhs):
  69. raise ValueError("Elliptic curve points have no ordering")
  70. def __ge__(self, rhs):
  71. raise ValueError("Elliptic curve points have no ordering")
  72. def __hash__(self):
  73. if self.infinite:
  74. return hash((True,))
  75. else:
  76. return hash((False, self.x, self.y))
  77. class CurveBase(object):
  78. def point(self, *args):
  79. return self.Point(self, *args)
  80. class WeierstrassCurve(CurveBase):
  81. class Point(AffinePoint):
  82. def check_equation(self):
  83. assert (self.y*self.y ==
  84. self.x*self.x*self.x +
  85. self.curve.a*self.x + self.curve.b)
  86. def __add__(self, rhs):
  87. if self.infinite:
  88. return rhs
  89. if rhs.infinite:
  90. return self
  91. if self.x == rhs.x and self.y != rhs.y:
  92. return self.curve.point()
  93. x1, x2, y1, y2 = self.x, rhs.x, self.y, rhs.y
  94. xdiff = x2-x1
  95. if xdiff != 0:
  96. slope = (y2-y1) / xdiff
  97. else:
  98. assert y1 == y2
  99. slope = (3*x1*x1 + self.curve.a) / (2*y1)
  100. xp = slope*slope - x1 - x2
  101. yp = -(y1 + slope * (xp-x1))
  102. return self.curve.point(xp, yp)
  103. def __init__(self, p, a, b):
  104. self.p = p
  105. self.a = ModP(p, a)
  106. self.b = ModP(p, b)
  107. def cpoint(self, x, yparity=0):
  108. if not hasattr(self, 'sqrtmodp'):
  109. self.sqrtmodp = RootModP(2, self.p)
  110. rhs = x**3 + self.a.n * x + self.b.n
  111. y = self.sqrtmodp.root(rhs)
  112. if (y - yparity) % 2:
  113. y = -y
  114. return self.point(x, y)
  115. def __repr__(self):
  116. return "{}(0x{:x}, {}, {})".format(
  117. type(self).__name__, self.p, self.a, self.b)
  118. class MontgomeryCurve(CurveBase):
  119. class Point(AffinePoint):
  120. def check_equation(self):
  121. assert (self.curve.b*self.y*self.y ==
  122. self.x*self.x*self.x +
  123. self.curve.a*self.x*self.x + self.x)
  124. def __add__(self, rhs):
  125. if self.infinite:
  126. return rhs
  127. if rhs.infinite:
  128. return self
  129. if self.x == rhs.x and self.y != rhs.y:
  130. return self.curve.point()
  131. x1, x2, y1, y2 = self.x, rhs.x, self.y, rhs.y
  132. xdiff = x2-x1
  133. if xdiff != 0:
  134. slope = (y2-y1) / xdiff
  135. elif y1 != 0:
  136. assert y1 == y2
  137. slope = (3*x1*x1 + 2*self.curve.a*x1 + 1) / (2*self.curve.b*y1)
  138. else:
  139. # If y1 was 0 as well, then we must have found an
  140. # order-2 point that doubles to the identity.
  141. return self.curve.point()
  142. xp = self.curve.b*slope*slope - self.curve.a - x1 - x2
  143. yp = -(y1 + slope * (xp-x1))
  144. return self.curve.point(xp, yp)
  145. def __init__(self, p, a, b):
  146. self.p = p
  147. self.a = ModP(p, a)
  148. self.b = ModP(p, b)
  149. def cpoint(self, x, yparity=0):
  150. if not hasattr(self, 'sqrtmodp'):
  151. self.sqrtmodp = RootModP(2, self.p)
  152. rhs = (x**3 + self.a.n * x**2 + x) / self.b
  153. y = self.sqrtmodp.root(int(rhs))
  154. if (y - yparity) % 2:
  155. y = -y
  156. return self.point(x, y)
  157. def __repr__(self):
  158. return "{}(0x{:x}, {}, {})".format(
  159. type(self).__name__, self.p, self.a, self.b)
  160. class TwistedEdwardsCurve(CurveBase):
  161. class Point(AffinePoint):
  162. def check_equation(self):
  163. x2, y2 = self.x*self.x, self.y*self.y
  164. assert (self.curve.a*x2 + y2 == 1 + self.curve.d*x2*y2)
  165. def __neg__(self):
  166. return type(self)(self.curve, -self.x, self.y)
  167. def __add__(self, rhs):
  168. x1, x2, y1, y2 = self.x, rhs.x, self.y, rhs.y
  169. x1y2, y1x2, y1y2, x1x2 = x1*y2, y1*x2, y1*y2, x1*x2
  170. dxxyy = self.curve.d*x1x2*y1y2
  171. return self.curve.point((x1y2+y1x2)/(1+dxxyy),
  172. (y1y2-self.curve.a*x1x2)/(1-dxxyy))
  173. def __init__(self, p, d, a):
  174. self.p = p
  175. self.d = ModP(p, d)
  176. self.a = ModP(p, a)
  177. def point(self, *args):
  178. # This curve form represents the identity using finite
  179. # numbers, so it doesn't need the special infinity flag.
  180. # Detect a no-argument call to point() and substitute the pair
  181. # of integers that gives the identity.
  182. if len(args) == 0:
  183. args = [0, 1]
  184. return super(TwistedEdwardsCurve, self).point(*args)
  185. def cpoint(self, y, xparity=0):
  186. if not hasattr(self, 'sqrtmodp'):
  187. self.sqrtmodp = RootModP(self.p)
  188. y = ModP(self.p, y)
  189. y2 = y**2
  190. radicand = (y2 - 1) / (self.d * y2 - self.a)
  191. x = self.sqrtmodp.root(radicand.n)
  192. if (x - xparity) % 2:
  193. x = -x
  194. return self.point(x, y)
  195. def __repr__(self):
  196. return "{}(0x{:x}, {}, {})".format(
  197. type(self).__name__, self.p, self.d, self.a)
  198. def find_montgomery_power2_order_x_values(p, a):
  199. # Find points on a Montgomery elliptic curve that have order a
  200. # power of 2.
  201. #
  202. # Motivation: both Curve25519 and Curve448 are abelian groups
  203. # whose overall order is a large prime times a small factor of 2.
  204. # The approved base point of each curve generates a cyclic
  205. # subgroup whose order is the large prime. Outside that cyclic
  206. # subgroup there are many other points that have large prime
  207. # order, plus just a handful that have tiny order. If one of the
  208. # latter is presented to you as a Diffie-Hellman public value,
  209. # nothing useful is going to happen, and RFC 7748 says we should
  210. # outlaw those values. And any actual attempt to outlaw them is
  211. # going to need to know what they are, either to check for each
  212. # one directly, or to use them as test cases for some other
  213. # approach.
  214. #
  215. # In a group of order p 2^k, an obvious way to search for points
  216. # with order dividing 2^k is to generate random group elements and
  217. # raise them to the power p. That guarantees that you end up with
  218. # _something_ with order dividing 2^k (even if it's boringly the
  219. # identity). And you also know from theory how many such points
  220. # you expect to exist, so you can count the distinct ones you've
  221. # found, and stop once you've got the right number.
  222. #
  223. # But that isn't actually good enough to find all the public
  224. # values that are problematic! The reason why not is that in
  225. # Montgomery key exchange we don't actually use a full elliptic
  226. # curve point: we only use its x-coordinate. And the formulae for
  227. # doubling and differential addition on x-coordinates can accept
  228. # some values that don't correspond to group elements _at all_
  229. # without detecting any error - and some of those nonsense x
  230. # coordinates can also behave like low-order points.
  231. #
  232. # (For example, the x-coordinate -1 in Curve25519 is such a value.
  233. # The reference ECC code in this module will raise an exception if
  234. # you call curve25519.cpoint(-1): it corresponds to no valid point
  235. # at all. But if you feed it into the doubling formula _anyway_,
  236. # it doubles to the valid curve point with x-coord 0, which in
  237. # turn doubles to the curve identity. Bang.)
  238. #
  239. # So we use an alternative approach which discards the group
  240. # theory of the actual elliptic curve, and focuses purely on the
  241. # doubling formula as an algebraic transformation on Z_p. Our
  242. # question is: what values of x have the property that if you
  243. # iterate the doubling map you eventually end up dividing by zero?
  244. # To answer that, we must solve cubics and quartics mod p, via the
  245. # code in numbertheory.py for doing so.
  246. E = EquationSolverModP(p)
  247. def viableSolutions(it):
  248. for x in it:
  249. try:
  250. yield int(x)
  251. except ValueError:
  252. pass # some field-extension element that isn't a real value
  253. def valuesDoublingTo(y):
  254. # The doubling formula for a Montgomery curve point given only
  255. # by x coordinate is (x+1)^2(x-1)^2 / (4(x^3+ax^2+x)).
  256. #
  257. # If we want to find a point that doubles to some particular
  258. # value, we can set that formula equal to y and expand to get the
  259. # quartic equation x^4 + (-4y)x^3 + (-4ay-2)x^2 + (-4y)x + 1 = 0.
  260. return viableSolutions(E.solve_monic_quartic(-4*y, -4*a*y-2, -4*y, 1))
  261. queue = []
  262. qset = set()
  263. pos = 0
  264. def insert(x):
  265. if x not in qset:
  266. queue.append(x)
  267. qset.add(x)
  268. # Our ultimate aim is to find points that end up going to the
  269. # curve identity / point at infinity after some number of
  270. # doublings. So our starting point is: what values of x make the
  271. # denominator of the doubling formula zero?
  272. for x in viableSolutions(E.solve_monic_cubic(a, 1, 0)):
  273. insert(x)
  274. while pos < len(queue):
  275. y = queue[pos]
  276. pos += 1
  277. for x in valuesDoublingTo(y):
  278. insert(x)
  279. return queue
  280. p256 = WeierstrassCurve(0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff, -3, 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b)
  281. p256.G = p256.point(0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296,0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5)
  282. p256.G_order = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551
  283. p384 = WeierstrassCurve(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff, -3, 0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef)
  284. p384.G = p384.point(0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7, 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f)
  285. p384.G_order = 0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973
  286. p521 = WeierstrassCurve(0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, -3, 0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00)
  287. p521.G = p521.point(0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66,0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650)
  288. p521.G_order = 0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409
  289. curve25519 = MontgomeryCurve(2**255-19, 0x76d06, 1)
  290. curve25519.G = curve25519.cpoint(9)
  291. curve448 = MontgomeryCurve(2**448-2**224-1, 0x262a6, 1)
  292. curve448.G = curve448.cpoint(5)
  293. ed25519 = TwistedEdwardsCurve(2**255-19, 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3, -1)
  294. ed25519.G = ed25519.point(0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a,0x6666666666666666666666666666666666666666666666666666666666666658)
  295. ed25519.G_order = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed
  296. ed448 = TwistedEdwardsCurve(2**448-2**224-1, -39081, +1)
  297. ed448.G = ed448.point(0x4f1970c66bed0ded221d15a622bf36da9e146570470f1767ea6de324a3d3a46412ae1af72ab66511433b80e18b00938e2626a82bc70cc05e,0x693f46716eb6bc248876203756c9c7624bea73736ca3984087789c1e05a0c2d73ad3ff1ce67c39c4fdbd132c4ed7c8ad9808795bf230fa14)
  298. ed448.G_order = 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3