Files
tea3-py/src/tea3/tea3model.py
T
2026-07-06 16:54:19 +02:00

153 lines
5.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from sage.all import GF, BooleanPolynomialRing
from functools import reduce
from operator import mul
from tea3.constants import TEA3_SBOX, T_F1, T_F2
from tea3.pretty_print import pretty_print, pretty_print_vec
class Tea3Model:
def __init__(self):
self.F = GF(2)
self.step_count = 0
names = (
[f"x{i}{j}" for i in range(5) for j in range(8)] + # 039
[f"y{i}{j}" for i in range(5) for j in range(8)] + # 4079
[f"r{i}{j}" for i in range(5) for j in range(8)] + # 80119
[f"R{i}{j}" for i in range(8) for j in range(8)] + # 120183
["g"] # 184
)
name_string = ",".join(names)
self.S = BooleanPolynomialRing(len(names), name_string)
self.v = self.S.gens()
self.x_bits = [list(self.v[i*8 : (i+1)*8 ]) for i in range(5)]
self.y_bits = [list(self.v[40 + i*8 : 40 + (i+1)*8 ]) for i in range(5)]
self.r_bits = [list(self.v[80 + i*8 : 80 + (i+1)*8 ]) for i in range(5)]
self.R_bits = [list(self.v[120 + i*8 : 120 + (i+1)*8]) for i in range(8)]
self.g = self.v[-1]
def _abstract_R(self):
"""
Abstract all monomials involving intermediate R variables.
For each polynomial in ``R_bits``, monomials containing any ``R`` or ``g`` variable are replaced with a variable ``g``.
Monomials involving only ``x``, ``y``, and ``r`` variables are kept unchanged.
"""
one = self.S.one()
zero = self.S.zero()
for i in range(8):
for j in range(8):
poly = self.R_bits[i][j]
groups = {}
pure_xyr = zero
const = one if bool(poly.constant_coefficient()) else zero
for monom in poly:
term_vars = monom.variables()
if not term_vars:
continue
xyr_vars = [v for v in term_vars if str(v)[0] in ('x', 'y', 'r')]
Rg_vars = [v for v in term_vars if str(v)[0] in ('R', 'g')]
xyr_mono = reduce(mul, (self.S(v) for v in xyr_vars), one)
xyr_key = frozenset(str(v) for v in xyr_vars)
if not Rg_vars:
pure_xyr += xyr_mono
else:
groups[xyr_key] = xyr_mono
result = pure_xyr + const
for xyr_key, xyr_mono in groups.items():
result += xyr_mono * self.g
self.R_bits[i][j] = result
def step(self, skip_abstract: bool = False):
R = self.R_bits.copy()
x = self.x_bits.copy()
r = self.r_bits.copy()
R0, R1, R2, R3, R4, R5, R6, R7 = R
x0, x1, x2, x3, x4 = x
r0, r1, r2, r3, r4 = r
# update r register
self.r_bits[0] = r1
self.r_bits[1] = r2
self.r_bits[2] = r3
self.r_bits[3] = r4
self.r_bits[4] = xor_vec(r0, S(r2))
# update x register
self.x_bits[0] = x1
self.x_bits[1] = x2
self.x_bits[2] = x3
self.x_bits[3] = x4
self.x_bits[4] = xor_vec(x0, r0)
# update R registers
self.R_bits[7] = R6
self.R_bits[6] = R5
self.R_bits[5] = xor_vec(R4, F31(R6, R5))
self.R_bits[4] = R3
self.R_bits[3] = R2
self.R_bits[2] = R1
self.R_bits[1] = R0
self.R_bits[0] = xor_vec(x0, xor_vec(R7, xor_vec(BP(R4), F32(R2, R1))))
if not skip_abstract:
self._abstract_R()
self.step_count += 1
return R7
def S(r):
# placeholder
return r
def xor_vec(a, b):
return [ai + bi for ai, bi in zip(a, b)]
def BP(r):
return [r[3], r[7], r[6], r[1], r[2], r[4], r[0], r[5]]
def F31(X, Y):
x0, x1, x2, x3, x4, x5, x6, x7 = X
y0, y1, y2, y3, y4, y5, y6, y7 = Y
return [
x5*x6*y5 + x5*x6 + x5*y5*y6 + x5*y5 + x5*y6 + x6*y5*y6 + y5*y6 + y5 + y6,
x6*x7*y6 + x6*x7 + x6*y6*y7 + x6*y7 + x6 + x7*y6 + x7*y7 + y6*y7 + y6 + y7 + 1,
x0*x7*y0 + x0*y0*y7 + x0*y0 + x0 + x7*y7 + y0,
x0*x1*y0 + x0*x1*y1 + x0*x1 + x0*y0*y1 + x0*y1 + x1*y0*y1 + x1 + y1,
x1*x2*y2 + x1*x2 + x1*y1 + x1*y2 + x2*y1*y2 + x2*y1 + x2 + y1*y2 + y1 + y2 + 1,
x2*x3*y3 + x2*y2 + x2 + x3*y2*y3 + x3*y3 + x3 + y2 + y3 + 1,
x3*x4*y4 + x3*y3 + x3*y4 + x4*y3*y4 + x4*y4 + x4 + y3*y4 + 1,
x4*x5*y5 + x4*y4*y5 + x4*y4 + x4*y5 + x5*y4*y5 + x5 + y5 + 1,
]
def F32(X, Y):
x0, x1, x2, x3, x4, x5, x6, x7 = X
y0, y1, y2, y3, y4, y5, y6, y7 = Y
return [
x5*x6*y5 + x5*x6 + x5*y5*y6 + x5*y5 + x5*y6 + x6*y5*y6 + y5 + y6 + 1,
x6*x7*y6 + x6*x7 + x6*y6*y7 + x6*y7 + x6 + x7*y7 + x7 + y6 + 1,
x0*x7*y0 + x0*x7*y7 + x0*y0*y7 + x0*y0 + x0 + x7*y0*y7 + y0,
x0*x1*y0 + x0*x1*y1 + x0*y0*y1 + x1*y0*y1 + x1*y0 + x1 + y0*y1 + y1,
x1*x2*y1 + x1*x2*y2 + x1*x2 + x1*y1*y2 + x1*y1 + x1 + x2*y1*y2 + x2 + y1*y2 + y2,
x2*x3*y3 + x2*y2 + x3*y2*y3 + x3*y3 + x3 + y3,
x3*x4*y4 + x3*x4 + x3*y3 + x3*y4 + x4*y3*y4 + x4*y3 + x4 + y3*y4 + y3 + y4,
x4*x5*y5 + x4*y4*y5 + x4*y4 + x5*y4*y5 + x5 + y4 + y5 + 1,
]