From f9608c1dbc3f40d14512f1808a5f59a214c8af0c Mon Sep 17 00:00:00 2001 From: Sam Hadow Date: Mon, 11 May 2026 11:56:10 +0200 Subject: [PATCH] lookup tables --- README.md | 6 ++++ pyproject.toml | 1 + src/tea3/lut.py | 80 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 src/tea3/lut.py diff --git a/README.md b/README.md index bb5c9ce..753c13c 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,12 @@ tea3-linear-bias tea3-differential-bias ``` +## derive lookup tables + +```bash +lookup-tables +``` + ## run sagemath script `deactivate` the venv first, then with sagemath installed: diff --git a/pyproject.toml b/pyproject.toml index c5f11d6..6dcfeb7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,3 +11,4 @@ testpaths = ["tests"] [project.scripts] tea3-linear-bias = "tea3.tea3linearbias:main" tea3-differential-bias = "tea3.tea3differentialbias:main" +lookup-tables = "tea3.lut:main" diff --git a/src/tea3/lut.py b/src/tea3/lut.py new file mode 100644 index 0000000..f94012a --- /dev/null +++ b/src/tea3/lut.py @@ -0,0 +1,80 @@ +from typing import Callable + +def pack_lut_4(f: Callable[..., int], order: tuple[int, int, int, int] = (0, 1, 2, 3)) -> int: + lut = 0 + for idx in range(16): + bits = [(idx >> i) & 1 for i in range(4)] # b0, b1, b2, b3 + args = [0, 0, 0, 0] + for bit_pos, arg_pos in enumerate(order): + args[arg_pos] = bits[bit_pos] + lut |= (f(*args) & 1) << idx + return lut + + +# F31 coordinates +def F31_0(x0, x1, y0, y1): + return (x0 & x1 & y0) ^ (x0 & x1) ^ (x0 & y0 & y1) ^ (x0 & y0) ^ (x0 & y1) ^ (x1 & y0 & y1) ^ (y0 & y1) ^ y0 ^ y1 + +def F31_1(x0, x1, y0, y1): + return (x0 & x1 & y0) ^ (x0 & x1) ^ (x0 & y0 & y1) ^ (x0 & y1) ^ x0 ^ (x1 & y0) ^ (x1 & y1) ^ (y0 & y1) ^ y0 ^ y1 ^ 1 + +def F31_2(x0, x1, y0, y1): + return (x0 & x1 & y0) ^ (x0 & y0 & y1) ^ (x0 & y0) ^ x0 ^ (x1 & y1) ^ y0 + +def F31_3(x0, x1, y0, y1): + return (x0 & x1 & y0) ^ (x0 & x1 & y1) ^ (x0 & x1) ^ (x0 & y0 & y1) ^ (x0 & y1) ^ (x1 & y0 & y1) ^ x1 ^ y1 + +def F31_4(x0, x1, y0, y1): + return (x0 & x1 & y1) ^ (x0 & x1) ^ (x0 & y0) ^ (x0 & y1) ^ (x1 & y0 & y1) ^ (x1 & y0) ^ x1 ^ (y0 & y1) ^ y0 ^ y1 ^ 1 + +def F31_5(x0, x1, y0, y1): + return (x0 & x1 & y1) ^ (x0 & y0) ^ x0 ^ (x1 & y0 & y1) ^ (x1 & y1) ^ x1 ^ y0 ^ y1 ^ 1 + +def F31_6(x0, x1, y0, y1): + return (x0 & x1 & y1) ^ (x0 & y0) ^ (x0 & y1) ^ (x1 & y0 & y1) ^ (x1 & y1) ^ x1 ^ (y0 & y1) ^ 1 + +def F31_7(x0, x1, y0, y1): + return (x0 & x1 & y1) ^ (x0 & y0 & y1) ^ (x0 & y0) ^ (x0 & y1) ^ (x1 & y0 & y1) ^ x1 ^ y1 ^ 1 + + +# F32 coordinates +def F32_0(x0, x1, y0, y1): + return (x0 & x1 & y0) ^ (x0 & x1) ^ (x0 & y0 & y1) ^ (x0 & y0) ^ (x0 & y1) ^ (x1 & y0 & y1) ^ y0 ^ y1 ^ 1 + +def F32_1(x0, x1, y0, y1): + return (x0 & x1 & y0) ^ (x0 & x1) ^ (x0 & y0 & y1) ^ (x0 & y1) ^ x0 ^ (x1 & y1) ^ x1 ^ y0 ^ 1 + +def F32_2(x0, x1, y0, y1): + return (x0 & x1 & y0) ^ (x0 & x1 & y1) ^ (x0 & y0 & y1) ^ (x0 & y0) ^ x0 ^ (x1 & y0 & y1) ^ y0 + +def F32_3(x0, x1, y0, y1): + return (x0 & x1 & y0) ^ (x0 & x1 & y1) ^ (x0 & y0 & y1) ^ (x1 & y0 & y1) ^ (x1 & y0) ^ x1 ^ (y0 & y1) ^ y1 + +def F32_4(x0, x1, y0, y1): + return (x0 & x1 & y0) ^ (x0 & x1 & y1) ^ (x0 & x1) ^ (x0 & y0 & y1) ^ (x0 & y0) ^ x0 ^ (x1 & y0 & y1) ^ x1 ^ (y0 & y1) ^ y1 + +def F32_5(x0, x1, y0, y1): + return (x0 & x1 & y1) ^ (x0 & y0) ^ (x1 & y0 & y1) ^ (x1 & y1) ^ x1 ^ y1 + +def F32_6(x0, x1, y0, y1): + return (x0 & x1 & y1) ^ (x0 & x1) ^ (x0 & y0) ^ (x0 & y1) ^ (x1 & y0 & y1) ^ (x1 & y0) ^ x1 ^ (y0 & y1) ^ y0 ^ y1 + +def F32_7(x0, x1, y0, y1): + return (x0 & x1 & y1) ^ (x0 & y0 & y1) ^ (x0 & y0) ^ (x1 & y0 & y1) ^ x1 ^ y0 ^ y1 ^ 1 + +def main(): + F31_coords = [F31_0, F31_1, F31_2, F31_3, F31_4, F31_5, F31_6, F31_7] + F32_coords = [F32_0, F32_1, F32_2, F32_3, F32_4, F32_5, F32_6, F32_7] + + lut_B = [pack_lut_4(f) for f in F31_coords] + lut_A = [pack_lut_4(f) for f in F32_coords] + + print("TEA3_LUT_A = [", end="") + for x in lut_A: + print(f"0x{x:04X}, ", end="") + print("]") + + print("TEA3_LUT_B = [", end="") + for x in lut_B: + print(f"0x{x:04X}, ", end="") + print("]")