📄 khash.py
字号:
# The contents of this file are subject to the BitTorrent Open Source License# Version 1.1 (the License). You may not copy or use this file, in either# source code or executable form, except in compliance with the License. You# may obtain a copy of the License at http://www.bittorrent.com/license/.## Software distributed under the License is distributed on an AS IS basis,# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License# for the specific language governing rights and limitations under the# License.from sha import shafrom random import randint#this is ugly, hopefully os.entropy will be in 2.4try: from entropy import entropyexcept ImportError: def entropy(n): s = '' for i in range(n): s += chr(randint(0,255)) return sdef intify(hstr): """20 bit hash, big-endian -> long python integer""" assert len(hstr) == 20 return long(hstr.encode('hex'), 16)def stringify(num): """long int -> 20-character string""" str = hex(num)[2:] if str[-1] == 'L': str = str[:-1] if len(str) % 2 != 0: str = '0' + str str = str.decode('hex') return (20 - len(str)) *'\x00' + str def distance(a, b): """distance between two 160-bit hashes expressed as 20-character strings""" return intify(a) ^ intify(b)def newID(): """returns a new pseudorandom globally unique ID string""" h = sha() h.update(entropy(20)) return h.digest()def newIDInRange(min, max): return stringify(randRange(min,max)) def randRange(min, max): return min + intify(newID()) % (max - min) def newTID(): return randRange(-2**30, 2**30)### Test Cases ###import unittestclass NewID(unittest.TestCase): def testLength(self): self.assertEqual(len(newID()), 20) def testHundreds(self): for x in xrange(100): self.testLengthclass Intify(unittest.TestCase): known = [('\0' * 20, 0), ('\xff' * 20, 2L**160 - 1), ] def testKnown(self): for str, value in self.known: self.assertEqual(intify(str), value) def testEndianessOnce(self): h = newID() while h[-1] == '\xff': h = newID() k = h[:-1] + chr(ord(h[-1]) + 1) self.assertEqual(intify(k) - intify(h), 1) def testEndianessLots(self): for x in xrange(100): self.testEndianessOnce()class Disantance(unittest.TestCase): known = [ (("\0" * 20, "\xff" * 20), 2**160L -1), ((sha("foo").digest(), sha("foo").digest()), 0), ((sha("bar").digest(), sha("bar").digest()), 0) ] def testKnown(self): for pair, dist in self.known: self.assertEqual(distance(pair[0], pair[1]), dist) def testCommutitive(self): for i in xrange(100): x, y, z = newID(), newID(), newID() self.assertEqual(distance(x,y) ^ distance(y, z), distance(x, z)) class RandRange(unittest.TestCase): def testOnce(self): a = intify(newID()) b = intify(newID()) if a < b: c = randRange(a, b) self.assertEqual(a <= c < b, 1, "output out of range %d %d %d" % (b, c, a)) else: c = randRange(b, a) assert b <= c < a, "output out of range %d %d %d" % (b, c, a) def testOneHundredTimes(self): for i in xrange(100): self.testOnce()if __name__ == '__main__': unittest.main()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -