tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

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