"""Lea 128-bit cipher."""
import itertools
from arxpy.bitvector.core import Constant
from arxpy.bitvector.operation import RotateLeft as ROL
from arxpy.bitvector.operation import RotateRight as ROR
from arxpy.primitives.primitives import KeySchedule, Encryption, Cipher
[docs]class LeaKeySchedule(KeySchedule):
"""Key schedule function."""
rounds = 24
input_widths = [32, 32, 32, 32]
output_widths = [32 for i in range(24 * 6)]
[docs] @classmethod
def set_rounds(cls, new_rounds):
cls.rounds = new_rounds
cls.output_widths = [32 for _ in range(new_rounds * 6)]
# noinspection PyPep8Naming
[docs] @classmethod
def eval(cls, k0, k1, k2, k3):
round_keys = [None for _ in range(cls.rounds)]
T0, T1, T2, T3 = k0, k1, k2, k3
delta = [
Constant(0xc3efe9db, 32), Constant(0x44626b02, 32),
Constant(0x79e27c8a, 32), Constant(0x78df30ec, 32),
]
for i in range(cls.rounds):
if hasattr(cls, "skip_rounds") and i in cls.skip_rounds:
round_keys[i] = k0, k0, k0, k0, k0, k0
continue
T0 = ROL(T0 + ROL(delta[i % 4], i), 1)
T1 = ROL(T1 + ROL(delta[i % 4], (i + 1)), 3)
T2 = ROL(T2 + ROL(delta[i % 4], (i + 2)), 6)
T3 = ROL(T3 + ROL(delta[i % 4], (i + 3)), 11)
round_keys[i] = T0, T1, T2, T1, T3, T1
return tuple(itertools.chain(*round_keys)) # flatten
[docs]class LeaEncryption(Encryption):
"""Encryption function."""
rounds = 24
input_widths = [32, 32, 32, 32]
output_widths = [32, 32, 32, 32]
round_keys = None
[docs] @classmethod
def set_rounds(cls, new_rounds):
cls.rounds = new_rounds
[docs] @classmethod
def eval(cls, p0, p1, p2, p3):
x0, x1, x2, x3 = p0, p1, p2, p3
rk = [[None for _ in range(6)] for _ in range(cls.rounds)]
for i, k in enumerate(cls.round_keys):
rk[i // 6][i % 6] = k
cls.round_inputs = []
for i in range(cls.rounds):
cls.round_inputs.append([x0, x1, x2, x3])
if hasattr(cls, "skip_rounds") and i in cls.skip_rounds:
continue
k0, k1, k2, k3, k4, k5 = rk[i]
tmp = x0
x0 = ROL((x0 ^ k0) + (x1 ^ k1), 9)
x1 = ROR((x1 ^ k2) + (x2 ^ k3), 5)
x2 = ROR((x2 ^ k4) + (x3 ^ k5), 3)
x3 = tmp
return x0, x1, x2, x3
[docs]class LeaCipher(Cipher):
key_schedule = LeaKeySchedule
encryption = LeaEncryption
rounds = 24
[docs] @classmethod
def set_rounds(cls, new_rounds):
cls.rounds = new_rounds
cls.key_schedule.set_rounds(new_rounds)
cls.encryption.set_rounds(new_rounds)
@classmethod
def set_skip_rounds(cls, skip_rounds):
cls.encryption.skip_rounds = skip_rounds
cls.key_schedule.skip_rounds = skip_rounds
@classmethod
def test(cls):
old_rounds = cls.rounds
cls.set_rounds(24)
key = [
Constant(0x3c2d1e0f, 32),
Constant(0x78695a4b, 32),
Constant(0xb4a59687, 32),
Constant(0xf0e1d2c3, 32)
]
pt = [
Constant(0x13121110, 32),
Constant(0x17161514, 32),
Constant(0x1b1a1918, 32),
Constant(0x1f1e1d1c, 32)
]
ct = [
Constant(0x354ec89f, 32),
Constant(0x18c6c628, 32),
Constant(0xa7c73255, 32),
Constant(0xfd8b6404, 32)
]
assert cls(pt, key) == tuple(ct)
cls.set_rounds(old_rounds)