siphash.py raw
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'))
66