|
""" |
|
Implementation of the SHAKE-256 algorithm for Ed448 |
|
""" |
|
|
|
try: |
|
import hashlib |
|
|
|
hashlib.new("shake256").digest(64) |
|
|
|
def shake_256(msg, outlen): |
|
return hashlib.new("shake256", msg).digest(outlen) |
|
|
|
except (TypeError, ValueError): |
|
|
|
from ._compat import bytes_to_int, int_to_bytes |
|
|
|
|
|
def _from_le(s): |
|
return bytes_to_int(s, byteorder="little") |
|
|
|
|
|
def _rol(x, b): |
|
return ((x << b) | (x >> (64 - b))) & (2**64 - 1) |
|
|
|
|
|
def _sha3_transform(s): |
|
ROTATIONS = [ |
|
0, |
|
1, |
|
62, |
|
28, |
|
27, |
|
36, |
|
44, |
|
6, |
|
55, |
|
20, |
|
3, |
|
10, |
|
43, |
|
25, |
|
39, |
|
41, |
|
45, |
|
15, |
|
21, |
|
8, |
|
18, |
|
2, |
|
61, |
|
56, |
|
14, |
|
] |
|
PERMUTATION = [ |
|
1, |
|
6, |
|
9, |
|
22, |
|
14, |
|
20, |
|
2, |
|
12, |
|
13, |
|
19, |
|
23, |
|
15, |
|
4, |
|
24, |
|
21, |
|
8, |
|
16, |
|
5, |
|
3, |
|
18, |
|
17, |
|
11, |
|
7, |
|
10, |
|
] |
|
RC = [ |
|
0x0000000000000001, |
|
0x0000000000008082, |
|
0x800000000000808A, |
|
0x8000000080008000, |
|
0x000000000000808B, |
|
0x0000000080000001, |
|
0x8000000080008081, |
|
0x8000000000008009, |
|
0x000000000000008A, |
|
0x0000000000000088, |
|
0x0000000080008009, |
|
0x000000008000000A, |
|
0x000000008000808B, |
|
0x800000000000008B, |
|
0x8000000000008089, |
|
0x8000000000008003, |
|
0x8000000000008002, |
|
0x8000000000000080, |
|
0x000000000000800A, |
|
0x800000008000000A, |
|
0x8000000080008081, |
|
0x8000000000008080, |
|
0x0000000080000001, |
|
0x8000000080008008, |
|
] |
|
|
|
for rnd in range(0, 24): |
|
|
|
c = [0] * 5 |
|
d = [0] * 5 |
|
for i in range(0, 25): |
|
c[i % 5] ^= s[i] |
|
for i in range(0, 5): |
|
d[i] = c[(i + 4) % 5] ^ _rol(c[(i + 1) % 5], 1) |
|
for i in range(0, 25): |
|
s[i] ^= d[i % 5] |
|
|
|
for i in range(0, 25): |
|
s[i] = _rol(s[i], ROTATIONS[i]) |
|
|
|
t = s[PERMUTATION[0]] |
|
for i in range(0, len(PERMUTATION) - 1): |
|
s[PERMUTATION[i]] = s[PERMUTATION[i + 1]] |
|
s[PERMUTATION[-1]] = t |
|
|
|
for i in range(0, 25, 5): |
|
t = [ |
|
s[i], |
|
s[i + 1], |
|
s[i + 2], |
|
s[i + 3], |
|
s[i + 4], |
|
s[i], |
|
s[i + 1], |
|
] |
|
for j in range(0, 5): |
|
s[i + j] = t[j] ^ ((~t[j + 1]) & (t[j + 2])) |
|
|
|
s[0] ^= RC[rnd] |
|
|
|
|
|
def _reinterpret_to_words_and_xor(s, b): |
|
for j in range(0, len(b) // 8): |
|
s[j] ^= _from_le(b[8 * j : 8 * j + 8]) |
|
|
|
|
|
def _reinterpret_to_octets(w): |
|
mp = bytearray() |
|
for j in range(0, len(w)): |
|
mp += int_to_bytes(w[j], 8, byteorder="little") |
|
return mp |
|
|
|
def _sha3_raw(msg, r_w, o_p, e_b): |
|
"""Semi-generic SHA-3 implementation""" |
|
r_b = 8 * r_w |
|
s = [0] * 25 |
|
|
|
idx = 0 |
|
blocks = len(msg) // r_b |
|
for i in range(0, blocks): |
|
_reinterpret_to_words_and_xor(s, msg[idx : idx + r_b]) |
|
idx += r_b |
|
_sha3_transform(s) |
|
|
|
m = bytearray(msg[idx:]) |
|
m.append(o_p) |
|
while len(m) < r_b: |
|
m.append(0) |
|
m[len(m) - 1] |= 128 |
|
|
|
_reinterpret_to_words_and_xor(s, m) |
|
_sha3_transform(s) |
|
|
|
out = bytearray() |
|
while len(out) < e_b: |
|
out += _reinterpret_to_octets(s[:r_w]) |
|
_sha3_transform(s) |
|
return out[:e_b] |
|
|
|
def shake_256(msg, outlen): |
|
return _sha3_raw(msg, 17, 31, outlen) |
|
|