slownacl_curve25519.py 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. # This is the curve25519 implementation from Matthew Dempsky's "Slownacl"
  2. # library. It is in the public domain.
  3. #
  4. # It isn't constant-time. Don't use it except for testing.
  5. #
  6. # Nick got the slownacl source from:
  7. # https://github.com/mdempsky/dnscurve/tree/master/slownacl
  8. __all__ = ['smult_curve25519_base', 'smult_curve25519']
  9. P = 2 ** 255 - 19
  10. A = 486662
  11. def expmod(b, e, m):
  12. if e == 0: return 1
  13. t = expmod(b, e / 2, m) ** 2 % m
  14. if e & 1: t = (t * b) % m
  15. return t
  16. def inv(x):
  17. return expmod(x, P - 2, P)
  18. # Addition and doubling formulas taken from Appendix D of "Curve25519:
  19. # new Diffie-Hellman speed records".
  20. def add((xn,zn), (xm,zm), (xd,zd)):
  21. x = 4 * (xm * xn - zm * zn) ** 2 * zd
  22. z = 4 * (xm * zn - zm * xn) ** 2 * xd
  23. return (x % P, z % P)
  24. def double((xn,zn)):
  25. x = (xn ** 2 - zn ** 2) ** 2
  26. z = 4 * xn * zn * (xn ** 2 + A * xn * zn + zn ** 2)
  27. return (x % P, z % P)
  28. def curve25519(n, base):
  29. one = (base,1)
  30. two = double(one)
  31. # f(m) evaluates to a tuple containing the mth multiple and the
  32. # (m+1)th multiple of base.
  33. def f(m):
  34. if m == 1: return (one, two)
  35. (pm, pm1) = f(m / 2)
  36. if (m & 1):
  37. return (add(pm, pm1, one), double(pm1))
  38. return (double(pm), add(pm, pm1, one))
  39. ((x,z), _) = f(n)
  40. return (x * inv(z)) % P
  41. def unpack(s):
  42. if len(s) != 32: raise ValueError('Invalid Curve25519 argument')
  43. return sum(ord(s[i]) << (8 * i) for i in range(32))
  44. def pack(n):
  45. return ''.join([chr((n >> (8 * i)) & 255) for i in range(32)])
  46. def clamp(n):
  47. n &= ~7
  48. n &= ~(128 << 8 * 31)
  49. n |= 64 << 8 * 31
  50. return n
  51. def smult_curve25519(n, p):
  52. n = clamp(unpack(n))
  53. p = unpack(p)
  54. return pack(curve25519(n, p))
  55. def smult_curve25519_base(n):
  56. n = clamp(unpack(n))
  57. return pack(curve25519(n, 9))
  58. #
  59. # This part I'm adding in for compatibility with the curve25519 python
  60. # module. -Nick
  61. #
  62. import os
  63. class Private:
  64. def __init__(self, secret=None, seed=None):
  65. self.private = pack(clamp(unpack(os.urandom(32))))
  66. def get_public(self):
  67. return Public(smult_curve25519_base(self.private))
  68. def get_shared_key(self, public, hashfn):
  69. return hashfn(smult_curve25519(self.private, public.public))
  70. def serialize(self):
  71. return self.private
  72. class Public:
  73. def __init__(self, public):
  74. self.public = public
  75. def serialize(self):
  76. return self.public