130 lines
2.5 KiB
Python
Executable File
130 lines
2.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import sys; assert sys.version_info[0] >= 3, "Python 3 required."
|
|
|
|
import math
|
|
import struct
|
|
|
|
from pyblake2 import blake2b
|
|
|
|
from tv_output import render_args, render_tv
|
|
from tv_rand import Rand
|
|
from utils import i2leosp
|
|
|
|
|
|
# Maximum output length of BLAKE2b
|
|
l_H = 64
|
|
assert 8*l_H == 512
|
|
|
|
MIN_l_M = 48
|
|
MAX_l_M = 4194368
|
|
assert MAX_l_M == 65537*l_H
|
|
|
|
def instantiate(l_L, l_R):
|
|
def H(i, u):
|
|
digest = blake2b(
|
|
digest_size=l_L,
|
|
person=b'UA_F4Jumble_H' + bytes([i, 0, 0]),
|
|
)
|
|
digest.update(u)
|
|
return digest.digest()
|
|
|
|
def G(i, u):
|
|
def inner(j):
|
|
digest = blake2b(
|
|
digest_size=l_H,
|
|
person=b'UA_F4Jumble_G' + bytes([i]) + i2leosp(16, j),
|
|
)
|
|
digest.update(u)
|
|
return digest.digest()
|
|
|
|
return b''.join([inner(j) for j in range(0, math.ceil(l_R/l_H))])[:l_R]
|
|
|
|
return (H, G)
|
|
|
|
def xor(x, y):
|
|
return bytes([a ^ b for (a, b) in zip(x, y)])
|
|
|
|
def f4jumble(M):
|
|
l_M = len(M)
|
|
assert MIN_l_M <= l_M and l_M <= MAX_l_M
|
|
|
|
l_L = min([l_H, l_M//2])
|
|
l_R = l_M - l_L
|
|
(H, G) = instantiate(l_L, l_R)
|
|
a = M[:l_L]
|
|
b = M[l_L:]
|
|
|
|
x = xor(b, G(0, a))
|
|
y = xor(a, H(0, x))
|
|
d = xor(x, G(1, y))
|
|
c = xor(y, H(1, d))
|
|
|
|
return c + d
|
|
|
|
def f4jumble_inv(M):
|
|
l_M = len(M)
|
|
assert MIN_l_M <= l_M and l_M <= MAX_l_M
|
|
|
|
l_L = min([l_H, l_M//2])
|
|
l_R = l_M - l_L
|
|
(H, G) = instantiate(l_L, l_R)
|
|
c = M[:l_L]
|
|
d = M[l_L:]
|
|
|
|
y = xor(c, H(1, d))
|
|
x = xor(d, G(1, y))
|
|
a = xor(y, H(0, x))
|
|
b = xor(x, G(0, a))
|
|
|
|
return a + b
|
|
|
|
|
|
def main():
|
|
args = render_args()
|
|
|
|
from random import Random
|
|
rng = Random(0xabad533d)
|
|
def randbytes(l):
|
|
ret = []
|
|
while len(ret) < l:
|
|
ret.append(rng.randrange(0, 256))
|
|
return bytes(ret)
|
|
rand = Rand(randbytes)
|
|
|
|
plain_test_vectors = []
|
|
|
|
# Generate test vectors with various lengths:
|
|
for l_M in [
|
|
MIN_l_M,
|
|
l_H,
|
|
2*l_H,
|
|
2*l_H + 1,
|
|
3*l_H,
|
|
3*l_H + 1,
|
|
257*l_H,
|
|
257*l_H + 1,
|
|
]:
|
|
M = rand.b(l_M)
|
|
jumbled = f4jumble(M)
|
|
assert len(jumbled) == len(M)
|
|
assert f4jumble_inv(jumbled) == M
|
|
|
|
plain_test_vectors.append({
|
|
'normal': M,
|
|
'jumbled': jumbled,
|
|
})
|
|
|
|
render_tv(
|
|
args,
|
|
'f4jumble',
|
|
(
|
|
('normal', 'Vec<u8>'),
|
|
('jumbled', 'Vec<u8>'),
|
|
),
|
|
plain_test_vectors,
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|