forked from XKCP/XKCP
-
Notifications
You must be signed in to change notification settings - Fork 0
/
M14.py
109 lines (101 loc) · 4.18 KB
/
M14.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# -*- coding: utf-8 -*-
# Implementation by DonaldTsang
#
# For more information, feedback or questions, please refer to our website:
# https://keccak.team/
#
# To the extent possible under law, the implementer has waived all copyright
# and related or neighboring rights to the source code in this file.
# http://creativecommons.org/publicdomain/zero/1.0/
def ROL64(a, n):
return ((a >> (64-(n%64))) + (a << (n%64))) % (1 << 64)
def KeccakP1600onLanes(lanes, nrRounds):
R = 1
for round in range(24):
if (round + nrRounds >= 24):
# θ
C = [lanes[x][0] ^ lanes[x][1] ^ lanes[x][2] ^ lanes[x][3] ^ lanes[x][4] for x in range(5)]
D = [C[(x+4)%5] ^ ROL64(C[(x+1)%5], 1) for x in range(5)]
lanes = [[lanes[x][y]^D[x] for y in range(5)] for x in range(5)]
# ρ and π
(x, y) = (1, 0)
current = lanes[x][y]
for t in range(24):
(x, y) = (y, (2*x+3*y)%5)
(current, lanes[x][y]) = (lanes[x][y], ROL64(current, (t+1)*(t+2)//2))
# χ
for y in range(5):
T = [lanes[x][y] for x in range(5)]
for x in range(5):
lanes[x][y] = T[x] ^((~T[(x+1)%5]) & T[(x+2)%5])
# ι
for j in range(7):
R = ((R << 1) ^ ((R >> 7)*0x71)) % 256
if (R & 2):
lanes[0][0] = lanes[0][0] ^ (1 << ((1<<j)-1))
else:
for j in range(7):
R = ((R << 1) ^ ((R >> 7)*0x71)) % 256
return lanes
def load64(b):
return sum((b[i] << (8*i)) for i in range(8))
def store64(a):
return bytearray((a >> (8*i)) % 256 for i in range(8))
def KeccakP1600(state, nrRounds):
lanes = [[load64(state[8*(x+5*y):8*(x+5*y)+8]) for y in range(5)] for x in range(5)]
lanes = KeccakP1600onLanes(lanes, nrRounds)
state = bytearray().join([store64(lanes[x][y]) for y in range(5) for x in range(5)])
return bytearray(state)
def F14(inputBytes, delimitedSuffix, outputByteLen):
outputBytes = bytearray()
state = bytearray([0 for i in range(200)])
rateInBytes = 1088//8
blockSize = 0
inputOffset = 0
# === Absorb all the input blocks ===
while(inputOffset < len(inputBytes)):
blockSize = min(len(inputBytes)-inputOffset, rateInBytes)
for i in range(blockSize):
state[i] = state[i] ^ inputBytes[i+inputOffset]
inputOffset = inputOffset + blockSize
if (blockSize == rateInBytes):
state = KeccakP1600(state, 14)
blockSize = 0
# === Do the padding and switch to the squeezing phase ===
state[blockSize] = state[blockSize] ^ delimitedSuffix
if (((delimitedSuffix & 0x80) != 0) and (blockSize == (rateInBytes-1))):
state = KeccakP1600(state, 14)
state[rateInBytes-1] = state[rateInBytes-1] ^ 0x80
state = KeccakP1600(state, 14)
# === Squeeze out all the output blocks ===
while(outputByteLen > 0):
blockSize = min(outputByteLen, rateInBytes)
outputBytes = outputBytes + state[0:blockSize]
outputByteLen = outputByteLen - blockSize
if (outputByteLen > 0):
state = KeccakP1600(state, 14)
return outputBytes
def right_encode(x):
S = bytearray()
while(x > 0):
S = bytearray([x % 256]) + S
x = x//256
S = S + bytearray([len(S)])
return S
# inputMessage and customizationString must be of type byte string or byte array
def MarsupilamiFourteen(inputMessage, customizationString, outputByteLen):
B = 8192
c = 512
S = bytearray(inputMessage) + bytearray(customizationString) + right_encode(len(customizationString))
# === Cut the input string into chunks of B bytes ===
n = (len(S)+B-1)//B
Si = [bytearray(S[i*B:(i+1)*B]) for i in range(n)]
if (n == 1):
# === Process the tree with only a final node ===
return F14(Si[0], 0x07, outputByteLen)
else:
# === Process the tree with kangaroo hopping ===
CVi = [F14(Si[i+1], 0x0B, c//8) for i in range(n-1)]
NodeStar = Si[0] + bytearray([3,0,0,0,0,0,0,0]) + bytearray().join(CVi) \
+ right_encode(n-1) + b'\xFF\xFF'
return F14(NodeStar, 0x06, outputByteLen)