siphash.py
1 #!/usr/bin/env python3 2 # Copyright (c) 2016-present The Bitcoin Core developers 3 # Distributed under the MIT software license, see the accompanying 4 # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 """SipHash-2-4 implementation. 6 7 This implements SipHash-2-4. For convenience, an interface taking 256-bit 8 integers is provided in addition to the one accepting generic data. 9 """ 10 11 def rotl64(n, b): 12 return n >> (64 - b) | (n & ((1 << (64 - b)) - 1)) << b 13 14 15 def siphash_round(v0, v1, v2, v3): 16 v0 = (v0 + v1) & ((1 << 64) - 1) 17 v1 = rotl64(v1, 13) 18 v1 ^= v0 19 v0 = rotl64(v0, 32) 20 v2 = (v2 + v3) & ((1 << 64) - 1) 21 v3 = rotl64(v3, 16) 22 v3 ^= v2 23 v0 = (v0 + v3) & ((1 << 64) - 1) 24 v3 = rotl64(v3, 21) 25 v3 ^= v0 26 v2 = (v2 + v1) & ((1 << 64) - 1) 27 v1 = rotl64(v1, 17) 28 v1 ^= v2 29 v2 = rotl64(v2, 32) 30 return (v0, v1, v2, v3) 31 32 33 def siphash(k0, k1, data): 34 assert type(data) is bytes 35 v0 = 0x736f6d6570736575 ^ k0 36 v1 = 0x646f72616e646f6d ^ k1 37 v2 = 0x6c7967656e657261 ^ k0 38 v3 = 0x7465646279746573 ^ k1 39 c = 0 40 t = 0 41 for d in data: 42 t |= d << (8 * (c % 8)) 43 c = (c + 1) & 0xff 44 if (c & 7) == 0: 45 v3 ^= t 46 v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3) 47 v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3) 48 v0 ^= t 49 t = 0 50 t = t | (c << 56) 51 v3 ^= t 52 v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3) 53 v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3) 54 v0 ^= t 55 v2 ^= 0xff 56 v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3) 57 v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3) 58 v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3) 59 v0, v1, v2, v3 = siphash_round(v0, v1, v2, v3) 60 return v0 ^ v1 ^ v2 ^ v3 61 62 63 def siphash256(k0, k1, num): 64 assert type(num) is int 65 return siphash(k0, k1, num.to_bytes(32, 'little'))