slownacl_curve25519.py (2844B)
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 9 # Future imports for Python 2.7, mandatory in 3.0 10 from __future__ import division 11 from __future__ import print_function 12 from __future__ import unicode_literals 13 14 import sys 15 16 __all__ = ['smult_curve25519_base', 'smult_curve25519'] 17 18 P = 2 ** 255 - 19 19 A = 486662 20 21 def expmod(b, e, m): 22 if e == 0: return 1 23 t = expmod(b, e // 2, m) ** 2 % m 24 if e & 1: t = (t * b) % m 25 return t 26 27 def inv(x): 28 return expmod(x, P - 2, P) 29 30 # Addition and doubling formulas taken from Appendix D of "Curve25519: 31 # new Diffie-Hellman speed records". 32 33 def add(n,m,d): 34 (xn,zn), (xm,zm), (xd,zd) = n, m, d 35 x = 4 * (xm * xn - zm * zn) ** 2 * zd 36 z = 4 * (xm * zn - zm * xn) ** 2 * xd 37 return (x % P, z % P) 38 39 def double(n): 40 (xn,zn) = n 41 x = (xn ** 2 - zn ** 2) ** 2 42 z = 4 * xn * zn * (xn ** 2 + A * xn * zn + zn ** 2) 43 return (x % P, z % P) 44 45 def curve25519(n, base): 46 one = (base,1) 47 two = double(one) 48 # f(m) evaluates to a tuple containing the mth multiple and the 49 # (m+1)th multiple of base. 50 def f(m): 51 if m == 1: return (one, two) 52 (pm, pm1) = f(m // 2) 53 if (m & 1): 54 return (add(pm, pm1, one), double(pm1)) 55 return (double(pm), add(pm, pm1, one)) 56 ((x,z), _) = f(n) 57 return (x * inv(z)) % P 58 59 if sys.version < '3': 60 def b2i(c): 61 return ord(c) 62 def i2b(i): 63 return chr(i) 64 def ba2bs(ba): 65 return "".join(ba) 66 else: 67 def b2i(c): 68 return c 69 def i2b(i): 70 return i 71 def ba2bs(ba): 72 return bytes(ba) 73 74 def unpack(s): 75 if len(s) != 32: raise ValueError('Invalid Curve25519 argument') 76 return sum(b2i(s[i]) << (8 * i) for i in range(32)) 77 78 def pack(n): 79 return ba2bs([i2b((n >> (8 * i)) & 255) for i in range(32)]) 80 81 def clamp(n): 82 n &= ~7 83 n &= ~(128 << 8 * 31) 84 n |= 64 << 8 * 31 85 return n 86 87 def smult_curve25519(n, p): 88 n = clamp(unpack(n)) 89 p = unpack(p) 90 return pack(curve25519(n, p)) 91 92 def smult_curve25519_base(n): 93 n = clamp(unpack(n)) 94 return pack(curve25519(n, 9)) 95 96 97 # 98 # This part I'm adding in for compatibility with the curve25519 python 99 # module. -Nick 100 # 101 import os 102 103 class Private: 104 def __init__(self, secret=None, seed=None): 105 self.private = pack(clamp(unpack(os.urandom(32)))) 106 107 def get_public(self): 108 return Public(smult_curve25519_base(self.private)) 109 110 def get_shared_key(self, public, hashfn): 111 return hashfn(smult_curve25519(self.private, public.public)) 112 113 def serialize(self): 114 return self.private 115 116 class Public: 117 def __init__(self, public): 118 self.public = public 119 120 def serialize(self): 121 return self.public