[tor-commits] [tor/master] slownacl's pure-python curve25519 lets us test ntor everywhere.

nickm at torproject.org nickm at torproject.org
Mon Feb 3 16:36:13 UTC 2014


commit 27d81c756b0e28266e75cf4cf897e486d11040b2
Author: Nick Mathewson <nickm at torproject.org>
Date:   Mon Feb 3 11:34:13 2014 -0500

    slownacl's pure-python curve25519 lets us test ntor everywhere.
    
    Improvement on f308adf8382bc7e61ea05a172, where we made the ntor
    unit tests run everywhere... so long as a python curve25519 module
    was installed.  Now the unit tests don't require that module.
---
 src/test/ntor_ref.py            |   19 ++++----
 src/test/slownacl_curve25519.py |   98 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 108 insertions(+), 9 deletions(-)

diff --git a/src/test/ntor_ref.py b/src/test/ntor_ref.py
index 2a5f984..12eb007 100755
--- a/src/test/ntor_ref.py
+++ b/src/test/ntor_ref.py
@@ -30,11 +30,12 @@ commands:
 import binascii
 try:
     import curve25519
+    curve25519mod = curve25519.keys
 except ImportError:
     curve25519 = None
-    print "SKIPPING: No Python curve25519 module installed"
-    import sys
-    sys.exit(0)
+    import slownacl_curve25519
+    curve25519mod = slownacl_curve25519
+
 import hashlib
 import hmac
 import subprocess
@@ -74,17 +75,17 @@ T_VERIFY = PROTOID + ":verify"
 def H_mac(msg): return H(msg, tweak=T_MAC)
 def H_verify(msg): return H(msg, tweak=T_VERIFY)
 
-class PrivateKey(curve25519.keys.Private):
-    """As curve25519.keys.Private, but doesn't regenerate its public key
+class PrivateKey(curve25519mod.Private):
+    """As curve25519mod.Private, but doesn't regenerate its public key
        every time you ask for it.
     """
     def __init__(self):
-        curve25519.keys.Private.__init__(self)
+        curve25519mod.Private.__init__(self)
         self._memo_public = None
 
     def get_public(self):
         if self._memo_public is None:
-            self._memo_public = curve25519.keys.Private.get_public(self)
+            self._memo_public = curve25519mod.Private.get_public(self)
 
         return self._memo_public
 
@@ -184,7 +185,7 @@ def server(seckey_b, my_node_id, message, keyBytes=72):
     badness = (keyid(seckey_b.get_public()) !=
                message[NODE_ID_LENGTH:NODE_ID_LENGTH+H_LENGTH])
 
-    pubkey_X = curve25519.keys.Public(message[NODE_ID_LENGTH+H_LENGTH:])
+    pubkey_X = curve25519mod.Public(message[NODE_ID_LENGTH+H_LENGTH:])
     seckey_y = PrivateKey()
     pubkey_Y = seckey_y.get_public()
     pubkey_B = seckey_b.get_public()
@@ -247,7 +248,7 @@ def client_part2(seckey_x, msg, node_id, pubkey_B, keyBytes=72):
     """
     assert len(msg) == G_LENGTH + H_LENGTH
 
-    pubkey_Y = curve25519.keys.Public(msg[:G_LENGTH])
+    pubkey_Y = curve25519mod.Public(msg[:G_LENGTH])
     their_auth = msg[G_LENGTH:]
 
     pubkey_X = seckey_x.get_public()
diff --git a/src/test/slownacl_curve25519.py b/src/test/slownacl_curve25519.py
new file mode 100644
index 0000000..25244fb
--- /dev/null
+++ b/src/test/slownacl_curve25519.py
@@ -0,0 +1,98 @@
+# This is the curve25519 implementation from Matthew Dempsky's "Slownacl"
+# library.  It is in the public domain.
+#
+# It isn't constant-time.  Don't use it except for testing.
+#
+# Nick got the slownacl source from:
+#        https://github.com/mdempsky/dnscurve/tree/master/slownacl
+
+__all__ = ['smult_curve25519_base', 'smult_curve25519']
+
+P = 2 ** 255 - 19
+A = 486662
+
+def expmod(b, e, m):
+  if e == 0: return 1
+  t = expmod(b, e / 2, m) ** 2 % m
+  if e & 1: t = (t * b) % m
+  return t
+
+def inv(x):
+  return expmod(x, P - 2, P)
+
+# Addition and doubling formulas taken from Appendix D of "Curve25519:
+# new Diffie-Hellman speed records".
+
+def add((xn,zn), (xm,zm), (xd,zd)):
+  x = 4 * (xm * xn - zm * zn) ** 2 * zd
+  z = 4 * (xm * zn - zm * xn) ** 2 * xd
+  return (x % P, z % P)
+
+def double((xn,zn)):
+  x = (xn ** 2 - zn ** 2) ** 2
+  z = 4 * xn * zn * (xn ** 2 + A * xn * zn + zn ** 2)
+  return (x % P, z % P)
+
+def curve25519(n, base):
+  one = (base,1)
+  two = double(one)
+  # f(m) evaluates to a tuple containing the mth multiple and the
+  # (m+1)th multiple of base.
+  def f(m):
+    if m == 1: return (one, two)
+    (pm, pm1) = f(m / 2)
+    if (m & 1):
+      return (add(pm, pm1, one), double(pm1))
+    return (double(pm), add(pm, pm1, one))
+  ((x,z), _) = f(n)
+  return (x * inv(z)) % P
+
+def unpack(s):
+  if len(s) != 32: raise ValueError('Invalid Curve25519 argument')
+  return sum(ord(s[i]) << (8 * i) for i in range(32))
+
+def pack(n):
+  return ''.join([chr((n >> (8 * i)) & 255) for i in range(32)])
+
+def clamp(n):
+  n &= ~7
+  n &= ~(128 << 8 * 31)
+  n |= 64 << 8 * 31
+  return n
+
+def smult_curve25519(n, p):
+  n = clamp(unpack(n))
+  p = unpack(p)
+  return pack(curve25519(n, p))
+
+def smult_curve25519_base(n):
+  n = clamp(unpack(n))
+  return pack(curve25519(n, 9))
+
+
+#
+# This part I'm adding in for compatibility with the curve25519 python
+# module. -Nick
+#
+import os
+
+class Private:
+    def __init__(self, secret=None, seed=None):
+        self.private = pack(clamp(unpack(os.urandom(32))))
+
+    def get_public(self):
+        return Public(smult_curve25519_base(self.private))
+
+    def get_shared_key(self, public, hashfn):
+        return hashfn(smult_curve25519(self.private, public.public))
+
+    def serialize(self):
+        return self.private
+
+class Public:
+    def __init__(self, public):
+        self.public = public
+
+    def serialize(self):
+        return self.public
+



More information about the tor-commits mailing list