# Implementation of the Lilliput-AE tweakable block cipher. # # Authors, hereby denoted as "the implementer": # Kévin Le Gouguec, # Léo Reynaud # 2019. # # For more information, feedback or questions, refer to our website: # https://paclido.fr/lilliput-ae # # To the extent possible under law, the implementer has waived all copyright # and related or neighboring rights to the source code in this file. # http://creativecommons.org/publicdomain/zero/1.0/ """Multiplications for Lilliput-TBC's tweakey schedule. This module provides a list of functions implementing lane multiplications, from ALPHAS[0] = α₀ = I to ALPHAS[6] = α₆ = M_R³. """ from functools import reduce from operator import xor def _Sl(n): return lambda xi: (xi<>n def _Id(xi): return xi def _0(xi): return 0 def _M1(xi): return (xi<<3 ^ xi>>3) & 0xff def _M2(xi): return (xi<<6 ^ (xi&0b11111000) ^ xi>>6) & 0xff M = ( ( _0, _Id, _0, _0, _0, _0, _0, _0), ( _0, _0, _Id, _0, _0, _0, _0, _0), ( _0, _0, _Sl(3), _Id, _0, _0, _0, _0), ( _0, _0, _0, _Sr(3), _Id, _0, _0, _0), ( _0, _0, _0, _0, _0, _Id, _0, _0), ( _0, _Sl(2), _0, _0, _0, _0, _Id, _0), ( _0, _0, _0, _0, _0, _0, _0, _Id), (_Id, _0, _0, _0, _0, _0, _0, _0), ) M2 = ( ( _0, _0, _Id, _0, _0, _0, _0, _0), ( _0, _0, _Sl(3), _Id, _0, _0, _0, _0), ( _0, _0, _Sl(6), _M1, _Id, _0, _0, _0), ( _0, _0, _0, _Sr(6), _Sr(3), _Id, _0, _0), ( _0, _Sl(2), _0, _0, _0, _0, _Id, _0), ( _0, _0, _Sl(2), _0, _0, _0, _0, _Id), (_Id, _0, _0, _0, _0, _0, _0, _0), ( _0, _Id, _0, _0, _0, _0, _0, _0), ) M3 = ( ( _0, _0, _Sl(3), _Id, _0, _0, _0, _0), ( _0, _0, _Sl(6), _M1, _Id, _0, _0, _0), ( _0, _0, _0, _M2, _M1, _Id, _0, _0), ( _0, _Sl(2), _0, _0, _Sr(6), _Sr(3), _Id, _0), ( _0, _0, _Sl(2), _0, _0, _0, _0, _Id), (_Id, _0, _Sl(5), _Sl(2), _0, _0, _0, _0), ( _0, _Id, _0, _0, _0, _0, _0, _0), ( _0, _0, _Id, _0, _0, _0, _0, _0), ) # NB: shift directions are reversed with respect to the specification # for powers of M_R, since the specification reverses the byte order # for those matrices. MR = ( ( _0, _Id, _0, _0, _0, _0, _0, _0), ( _0, _0, _Id, _0, _0, _0, _0, _0), ( _0, _0, _0, _Id, _Sr(3), _0, _0, _0), ( _0, _0, _0, _0, _Id, _0, _0, _0), ( _0, _0, _0, _0, _0, _Id, _Sl(3), _0), ( _0, _0, _0, _Sl(2), _0, _0, _Id, _0), ( _0, _0, _0, _0, _0, _0, _0, _Id), (_Id, _0, _0, _0, _0, _0, _0, _0), ) def _multiplication(m, reverse=True): def ordered(l): if reverse: return list(reversed(list(l))) return l def _multiply(x): return ordered( reduce(xor, (mj[i](xi) for i, xi in enumerate(ordered(x)))) for mj in m ) return _multiply def _multiply_MR2(lane): multiplied_lane = [lane[(byte+2) % 8] for byte in range(0, 8)] multiplied_lane[1] ^= ((lane[4] >> 3) & 0xff) multiplied_lane[2] ^= ((lane[5] >> 3) & 0xff) multiplied_lane[3] ^= ((lane[6] << 3) & 0xff) multiplied_lane[4] ^= ((lane[3] << 2) & 0xff) ^ ((lane[7] << 3) & 0xff) multiplied_lane[5] ^= ((lane[4] << 2) & 0xff) # binary matrix m3 multi_mat_l6_m3 = 0 l6 = lane[6] multi_mat_l6_m3 ^= (l6 & 0x1) multi_mat_l6_m3 ^= (l6 & 0x2) multi_mat_l6_m3 ^= (l6 & 0x4) multi_mat_l6_m3 ^= (l6 & 0x8) multi_mat_l6_m3 ^= (l6 & 0x10) multiplied_lane[2] ^= multi_mat_l6_m3 return multiplied_lane def _multiply_MR3(lane): multiplied_lane = [lane[(byte+3) % 8] for byte in range(0, 8)] multiplied_lane[0] ^= ((lane[4] >> 3) & 0xff) multiplied_lane[1] ^= ((lane[5] >> 3) & 0xff) multiplied_lane[3] ^= ((lane[3] << 2) & 0xff) ^ ((lane[7] << 3) & 0xff) multiplied_lane[4] ^= ((lane[0] << 3) & 0xff) ^ ((lane[4] << 2) & 0xff) multiplied_lane[5] ^= ((lane[5] << 2) & 0xff) ^ ((lane[6] << 5) & 0xff) # binary matrix m3 multi_mat_l6_m3 = 0 l6 = lane[6] multi_mat_l6_m3 ^= (l6 & 0x1) multi_mat_l6_m3 ^= (l6 & 0x2) multi_mat_l6_m3 ^= (l6 & 0x4) multi_mat_l6_m3 ^= (l6 & 0x8) multi_mat_l6_m3 ^= (l6 & 0x10) # binary matrix m3 multi_mat_l7_m3 = 0 l7 = lane[7] multi_mat_l7_m3 ^= (l7 & 0x1) multi_mat_l7_m3 ^= (l7 & 0x2) multi_mat_l7_m3 ^= (l7 & 0x4) multi_mat_l7_m3 ^= (l7 & 0x8) multi_mat_l7_m3 ^= (l7 & 0x10) # binary matrix m4 multi_mat_l3_m4 = 0 l3 = lane[3] multi_mat_l3_m4 ^= ((l3 & 0x2) >> 1) multi_mat_l3_m4 ^= ((l3 & 0x4) >> 1) multi_mat_l3_m4 ^= ((l3 & 0x8) >> 1) multi_mat_l3_m4 ^= ((l3 & 0x10) >> 1) multi_mat_l3_m4 ^= ((l3 & 0x20) >> 1) # binary matrix m1 for MR multi_mat_l6_m1 = 0 l6 = lane[6] multi_mat_l6_m1 ^= ((l6 & 0x8) >> 3) multi_mat_l6_m1 ^= ((l6 & 0x10) >> 3) multi_mat_l6_m1 ^= ((l6 & 0x20) >> 3) multi_mat_l6_m1 ^= ((l6 & 0x40) >> 3) ^ ((l6 & 0x1) << 3) multi_mat_l6_m1 ^= ((l6 & 0x80) >> 3) ^ ((l6 & 0x2) << 3) multi_mat_l6_m1 ^= ((l6 & 0x4) << 3) multi_mat_l6_m1 ^= ((l6 & 0x8) << 3) multi_mat_l6_m1 ^= ((l6 & 0x10) << 3) multiplied_lane[1] ^= multi_mat_l6_m3 multiplied_lane[2] ^= multi_mat_l3_m4 ^ multi_mat_l6_m1 ^ multi_mat_l7_m3 return multiplied_lane ALPHAS = ( list, # Identity. _multiplication(M), _multiplication(M2), _multiplication(M3), _multiplication(MR, reverse=False), _multiply_MR2, _multiply_MR3 )