]> git.mxchange.org Git - quix0rs-apt-p2p.git/blobdiff - apt_p2p_Khashmir/khash.py
Final version of abstract.
[quix0rs-apt-p2p.git] / apt_p2p_Khashmir / khash.py
index 91db232d375549a163943c552e2d25bc4eaef163..65670af9605805dfa4af73c96522dec382f426d0 100644 (file)
@@ -1,16 +1,19 @@
-## Copyright 2002-2003 Andrew Loewenstern, All Rights Reserved
-# see LICENSE.txt for license information
 
-"""Functions to deal with hashes (node IDs and keys)."""
+"""Functions to deal with hashes (node IDs and keys).
+
+@var HASH_LENGTH: the length of the hash to use in bytes
+"""
 
 from sha import sha
 from os import urandom
 
 from twisted.trial import unittest
 
+HASH_LENGTH = 20
+
 def intify(hstr):
     """Convert a hash (big-endian) to a long python integer."""
-    assert len(hstr) == 20
+    assert len(hstr) == HASH_LENGTH
     return long(hstr.encode('hex'), 16)
 
 def stringify(num):
@@ -21,17 +24,24 @@ def stringify(num):
     if len(str) % 2 != 0:
         str = '0' + str
     str = str.decode('hex')
-    return (20 - len(str)) *'\x00' + str
+    return (HASH_LENGTH - len(str)) *'\x00' + str
     
 def distance(a, b):
     """Calculate the distance between two hashes expressed as strings."""
     return intify(a) ^ intify(b)
 
-def newID():
-    """Get a new pseudorandom globally unique hash string."""
+def newID(suffix = ''):
+    """Get a new pseudorandom globally unique hash string.
+    
+    @param suffix: an optional string to end the ID with
+    """
+    assert len(suffix) < 20, 'The suffix must be shorter than the SHA1 hash'
     h = sha()
-    h.update(urandom(20))
-    return h.digest()
+    h.update(urandom(HASH_LENGTH))
+    if suffix:
+        return h.digest()[:-len(suffix)] + suffix
+    else:
+        return h.digest()
 
 def newIDInRange(min, max):
     """Get a new pseudorandom globally unique hash string in the range."""
@@ -48,15 +58,19 @@ def newTID():
 class TestNewID(unittest.TestCase):
     """Test the newID function."""
     def testLength(self):
-        self.failUnlessEqual(len(newID()), 20)
+        self.failUnlessEqual(len(newID()), HASH_LENGTH)
     def testHundreds(self):
         for x in xrange(100):
-            self.testLength
+            self.testLength()
+    def testSuffix(self):
+        id = newID('T012')
+        self.failUnlessEqual(len(id), HASH_LENGTH)
+        self.failUnlessEqual(id[-4:], 'T012')
 
 class TestIntify(unittest.TestCase):
     """Test the intify function."""
-    known = [('\0' * 20, 0),
-            ('\xff' * 20, 2L**160 - 1),
+    known = [('\0' * HASH_LENGTH, 0),
+            ('\xff' * HASH_LENGTH, 2L**(HASH_LENGTH*8) - 1),
             ]
     def testKnown(self):
         for str, value in self.known: 
@@ -74,7 +88,7 @@ class TestIntify(unittest.TestCase):
 class TestDisantance(unittest.TestCase):
     """Test the distance function."""
     known = [
-            (("\0" * 20, "\xff" * 20), 2**160L -1),
+            (("\0" * HASH_LENGTH, "\xff" * HASH_LENGTH), 2L**(HASH_LENGTH*8) -1),
             ((sha("foo").digest(), sha("foo").digest()), 0),
             ((sha("bar").digest(), sha("bar").digest()), 0)
             ]