from TurboSHAKE import ROL64, load64, store64, KeccakP1600, KeccakP1600onLanes, TurboSHAKE128, TurboSHAKE256
from K12 import right_encode
def KeccakP1600timesN_SIMD(N, states, nrRounds):
R = 1
for round in range(24):
if (round + nrRounds >= 24):
C = [[states[x][0][i] ^ states[x][1][i] ^ states[x][2][i] ^ states[x][3][i] ^ states[x][4][i] for i in range(N)] for x in range(5)]
D = [[C[(x+4)%5][i] ^ ROL64(C[(x+1)%5][i], 1) for i in range(N)] for x in range(5)]
states = [[[states[x][y][i]^D[x][i] for i in range(N)] for y in range(5)] for x in range(5)]
(x, y) = (1, 0)
current = [states[x][y][i] for i in range(N)]
for t in range(24):
(x, y) = (y, (2*x+3*y)%5)
(current, states[x][y]) = (states[x][y], [ROL64(current[i], (t+1)*(t+2)//2) for i in range(N)])
for y in range(5):
T = [states[x][y] for x in range(5)]
for x in range(5):
states[x][y] = [T[x][i] ^((~T[(x+1)%5][i]) & T[(x+2)%5][i]) for i in range(N)]
for j in range(7):
R = ((R << 1) ^ ((R >> 7)*0x71)) % 256
if (R & 2):
states[0][0] = [states[0][0][i] ^ (1 << ((1<<j)-1)) for i in range(N)]
else:
for j in range(7):
R = ((R << 1) ^ ((R >> 7)*0x71)) % 256
return states
def KeccakP1600timesN_AddLanesAll(N, states, data, laneCount, laneOffset):
assert(len(data) >= 8*((N-1)*laneOffset + laneCount))
for y in range(5):
for x in range(5):
xy = x + 5*y
if (xy < laneCount):
loadedData = [load64(data[8*(i*laneOffset + xy) : 8*(i*laneOffset + xy + 1)]) for i in range(N)]
states[x][y] = [states[x][y][i] ^ loadedData[i] for i in range(N)]
return states
B = 8192
def KT128_ProcessLeaves(N, data):
assert(len(data) >= N*B)
rateInLanes = 21
rateInBytes = rateInLanes*8
A = [[[0 for i in range(N)] for y in range(5)] for x in range(5)]
for j in range(0, B - rateInBytes, rateInBytes):
KeccakP1600timesN_AddLanesAll(N, A, data[j:], rateInLanes, B//8)
A = KeccakP1600timesN_SIMD(N, A, 12)
j = (B//rateInBytes)*rateInBytes
KeccakP1600timesN_AddLanesAll(N, A, data[j:], (B - j)//8, B//8)
A[1][3] = [A[1][3][i] ^ 0x0B for i in range(N)]
A[0][4] = [A[0][4][i] ^ 0x8000000000000000 for i in range(N)]
A = KeccakP1600timesN_SIMD(N, A, 12)
CVs = bytearray().join([store64(A[0][0][i]) + store64(A[1][0][i]) + store64(A[2][0][i]) + store64(A[3][0][i]) for i in range(N)])
return CVs
def KT256_ProcessLeaves(N, data):
assert(len(data) >= N*B)
rateInLanes = 17
rateInBytes = rateInLanes*8
A = [[[0 for i in range(N)] for y in range(5)] for x in range(5)]
for j in range(0, B - rateInBytes, rateInBytes):
KeccakP1600timesN_AddLanesAll(N, A, data[j:], rateInLanes, B//8)
A = KeccakP1600timesN_SIMD(N, A, 12)
j = (B//rateInBytes)*rateInBytes
KeccakP1600timesN_AddLanesAll(N, A, data[j:], (B - j)//8, B//8)
A[4][0] = [A[4][0][i] ^ 0x0B for i in range(N)]
A[1][3] = [A[1][3][i] ^ 0x8000000000000000 for i in range(N)]
A = KeccakP1600timesN_SIMD(N, A, 12)
CVs = bytearray().join([
store64(A[0][0][i]) + store64(A[1][0][i]) + store64(A[2][0][i]) + store64(A[3][0][i]) +
store64(A[4][0][i]) + store64(A[0][1][i]) + store64(A[1][1][i]) + store64(A[2][1][i])
for i in range(N)])
return CVs
def KT128(inputMessage, customizationString, outputByteLen):
c = 256
S = bytearray(inputMessage) + bytearray(customizationString) + right_encode(len(customizationString))
if (len(S) <= B):
return TurboSHAKE128(S, 0x07, outputByteLen)
else:
CVs = bytearray()
j = B
n = 0
while(j + 8*B <= len(S)):
CVs = CVs + KT128_ProcessLeaves(8, S[j:])
j = j + 8*B
n = n + 8
while(j + 4*B <= len(S)):
CVs = CVs + KT128_ProcessLeaves(4, S[j:])
j = j + 4*B
n = n + 4
while(j + 2*B <= len(S)):
CVs = CVs + KT128_ProcessLeaves(2, S[j:])
j = j + 2*B
n = n + 2
while(j < len(S)):
CVs = CVs + TurboSHAKE128(S[j:j+B], 0x0B, c//8)
j = j + B
n = n + 1
NodeStar = S[0:B] + bytearray([3,0,0,0,0,0,0,0]) + CVs \
+ right_encode(n) + b'\xFF\xFF'
return TurboSHAKE128(NodeStar, 0x06, outputByteLen)
def KT256(inputMessage, customizationString, outputByteLen):
c = 512
S = bytearray(inputMessage) + bytearray(customizationString) + right_encode(len(customizationString))
if (len(S) <= B):
return TurboSHAKE256(S, 0x07, outputByteLen)
else:
CVs = bytearray()
j = B
n = 0
while(j + 8*B <= len(S)):
CVs = CVs + KT256_ProcessLeaves(8, S[j:])
j = j + 8*B
n = n + 8
while(j + 4*B <= len(S)):
CVs = CVs + KT256_ProcessLeaves(4, S[j:])
j = j + 4*B
n = n + 4
while(j + 2*B <= len(S)):
CVs = CVs + KT256_ProcessLeaves(2, S[j:])
j = j + 2*B
n = n + 2
while(j < len(S)):
CVs = CVs + TurboSHAKE256(S[j:j+B], 0x0B, c//8)
j = j + B
n = n + 1
NodeStar = S[0:B] + bytearray([3,0,0,0,0,0,0,0]) + CVs \
+ right_encode(n) + b'\xFF\xFF'
return TurboSHAKE256(NodeStar, 0x06, outputByteLen)
def Test_KeccakP1600timesN_SIMD():
for N in range(1, 5):
print("Testing KeccakP1600timesN_SIMD for N =", N)
lanes = [[[(x+y+i+x*y*i) % (2**64) for i in range(N)] for y in range(5)] for x in range(5)]
lanes_t = [[[lanes[x][y][i] for y in range(5)] for x in range(5)] for i in range(N)]
ref_lanes_t = [KeccakP1600onLanes(lanes_t[i], 24) for i in range(N)]
ref_lanes = [[[ref_lanes_t[i][x][y] for i in range(N)] for y in range(5)] for x in range(5)]
test_lanes = KeccakP1600timesN_SIMD(N, lanes, 24)
assert(ref_lanes == test_lanes)
return
def Test_KT128_ProcessLeaves():
c = 256
for N in range(1, 5):
print("Testing KT128_ProcessLeaves for N =", N)
S = bytearray([(i%247) for i in range(B*N)])
Si = [bytearray(S[i*B:(i+1)*B]) for i in range(N)]
ref_CVs = bytearray().join([TurboSHAKE128(Si[i], 0x0B, c//8) for i in range(N)])
test_CVs = KT128_ProcessLeaves(N, S)
assert(test_CVs == ref_CVs)
def outputHex(s):
for i in range(len(s)):
print("{0:02x}".format(s[i]), end=' ')
print()
print()
def ptn(n):
pattern = bytes(range(0xFA + 1)) repetitions = n // len(pattern)
remainder = n % len(pattern)
repeated_pattern = pattern * repetitions + pattern[:remainder]
return repeated_pattern
def printKT128TestVectors():
print("KT128(M=empty, C=empty, 32 output bytes):")
outputHex(KT128(b'', b'', 32))
print("KT128(M=empty, C=empty, 64 output bytes):")
outputHex(KT128(b'', b'', 64))
print("KT128(M=empty, C=empty, 10032 output bytes), last 32 bytes:")
outputHex(KT128(b'', b'', 10032)[10000:])
for i in range(6):
C = b''
M = ptn(17**i)
print("KT128(M=pattern 0x00 to 0xFA for 17^{0:d} bytes, C=empty, 32 output bytes):".format(i))
outputHex(KT128(M, C, 32))
for i in range(4):
M = bytearray([0xFF for j in range(2**i-1)])
C = ptn(41**i)
print("KT128(M={0:d} times byte 0xFF, C=pattern 0x00 to 0xFA for 41^{1:d} bytes, 32 output bytes):".format(2**i-1, i))
outputHex(KT128(M, C, 32))
def printKT256TestVectors():
print("KT256(M=empty, C=empty, 64 output bytes):")
outputHex(KT256(b'', b'', 64))
print("KT256(M=empty, C=empty, 128 output bytes):")
outputHex(KT256(b'', b'', 128))
for i in range(6):
C = b''
M = ptn(17**i)
print("KT256(M=pattern 0x00 to 0xFA for 17^{0:d} bytes, C=empty, 64 output bytes):".format(i))
outputHex(KT256(M, C, 64))
for i in range(4):
M = bytearray([0xFF for j in range(2**i-1)])
C = ptn(41**i)
print("KT256(M={0:d} times byte 0xFF, C=pattern 0x00 to 0xFA for 41^{1:d} bytes, 64 output bytes):".format(2**i-1, i))
outputHex(KT256(M, C, 64))
Test_KeccakP1600timesN_SIMD()
Test_KT128_ProcessLeaves()
printKT128TestVectors()
printKT256TestVectors()