summaryrefslogtreecommitdiff
path: root/python/lilliput/tbc.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/lilliput/tbc.py')
-rw-r--r--python/lilliput/tbc.py178
1 files changed, 178 insertions, 0 deletions
diff --git a/python/lilliput/tbc.py b/python/lilliput/tbc.py
new file mode 100644
index 0000000..5291994
--- /dev/null
+++ b/python/lilliput/tbc.py
@@ -0,0 +1,178 @@
+"""
+ Lilliput TBC
+"""
+from .constants import BLOCK_BYTES, Sbox
+from .multiplications import ALPHAS
+
+
+permutation = [14, 11, 12, 10, 8, 9, 13, 15, 3, 1, 4, 5, 6, 0, 2, 7]
+permutationInv = [13, 9, 14, 8, 10, 11, 12, 15, 4, 5, 3, 1, 2, 6 ,0 ,7]
+
+################################################################################
+
+def BuildTweakey(tweak, key):
+ return tweak+key
+
+#############################
+
+def _lane(TK, j):
+ return TK[j*8:(j+1)*8]
+
+def RoundTweakeySchedule(tweakey):
+ p = len(tweakey)//8
+
+ multiplied_lanes = (
+ ALPHAS[j](_lane(tweakey, j)) for j in range(p)
+ )
+
+ return [byte for lane in multiplied_lanes for byte in lane]
+
+
+def SubTweakeyExtract(tweakey, Ci):
+ RTKi = [0]*8
+
+ for j, byte in enumerate(tweakey):
+ RTKi[j%8] ^= byte
+
+ RTKi[0] ^= Ci
+
+ return RTKi
+
+
+def TweakeyScheduleWhole(tweakey, r):
+ # store main tweakey in TKs[0]
+ # and corresponding round tweakey in RTKs[0]
+ TKs = [tweakey]
+ RTKs = [SubTweakeyExtract(TKs[0], 0)]
+
+ for i in range(1, r):
+ TKs.append(RoundTweakeySchedule(TKs[i-1]))
+ RTKs.append(SubTweakeyExtract(TKs[i], i))
+
+ return RTKs
+
+
+################################################################################
+
+def NonLinearLayer(state, subtweakey):
+
+ variables_xored = [0 for byte in range(0, 8)]
+ for byte in range(0,8):
+ variables_xored[byte] = state[byte] ^ subtweakey[byte]
+
+ variables_sboxed = [0 for byte in range(0, 8)]
+ for byte in range(0, 8):
+ variables_sboxed[byte] = Sbox[variables_xored[byte]]
+
+ state_output = [0 for byte in range(0, BLOCK_BYTES)]
+ for byte in range(0,BLOCK_BYTES):
+ state_output[byte] = state[byte]
+ for byte in range(0, 8):
+ state_output[15 - byte] ^= variables_sboxed[byte]
+
+ return state_output
+
+
+def LinearLayer(state):
+ state_output = [0 for byte in range(0, BLOCK_BYTES)]
+ for byte in range(0, BLOCK_BYTES):
+ state_output[byte] = state[byte]
+
+ for byte in range(1, 8):
+ state_output[15] ^= state[byte]
+
+ for byte in range(9, 15):
+ state_output[byte] ^= state[7]
+
+ return state_output
+
+
+def PermutationLayerEnc(state):
+ state_output = [0 for byte in range(0, BLOCK_BYTES)]
+ for byte in range(0, BLOCK_BYTES):
+ state_output[byte] = state[permutation[byte]]
+
+ return state_output
+
+def PermutationLayerDec(state):
+ state_output = [0 for byte in range(0, BLOCK_BYTES)]
+ for byte in range(0, BLOCK_BYTES):
+ state_output[byte] = state[permutationInv[byte]]
+
+ return state_output
+
+
+def OneRoundEGFNEnc(state, subtweakey):
+ state_non_linear = NonLinearLayer(state, subtweakey)
+ state_linear = LinearLayer(state_non_linear)
+ state_permutation = PermutationLayerEnc(state_linear)
+
+ return state_permutation
+
+def LastRoundEGFN(state, subtweakey):
+ state_non_linear = NonLinearLayer(state, subtweakey)
+ state_linear = LinearLayer(state_non_linear)
+
+ return state_linear
+
+
+def OneRoundEGFNDec(state, subtweakey):
+ state_non_linear = NonLinearLayer(state, subtweakey)
+ state_linear = LinearLayer(state_non_linear)
+ state_permutation = PermutationLayerDec(state_linear)
+
+ return state_permutation
+
+
+def _rounds(key_bytes):
+ rounds = {
+ 128: 32,
+ 192: 36,
+ 256: 42
+ }
+ return rounds[key_bytes*8]
+
+
+################################################################################
+# Lilliput TBC
+
+def encrypt(tweak, key, message):
+ r = _rounds(len(key))
+
+ tweakey = BuildTweakey(tweak, key)
+ RTKs = TweakeyScheduleWhole(tweakey, r)
+
+ state = [0 for byte in range(0, BLOCK_BYTES)]
+ for byte in range(0, BLOCK_BYTES):
+ state[byte] = message[byte]
+
+ for i in range(0, r-1):
+ state_output = OneRoundEGFNEnc(state, RTKs[i])
+
+ for byte in range(0, BLOCK_BYTES):
+ state[byte] = state_output[byte]
+
+ state_output = LastRoundEGFN(state, RTKs[r-1])
+
+ return state_output
+
+
+def decrypt(tweak, key, cipher):
+ r = _rounds(len(key))
+
+ tweakey = BuildTweakey(tweak, key)
+ RTKs = TweakeyScheduleWhole(tweakey, r)
+
+ state = [0 for byte in range(0, BLOCK_BYTES)]
+ for byte in range(0, BLOCK_BYTES):
+ state[byte] = cipher[byte]
+
+ for i in range(0, r-1):
+ state_output = OneRoundEGFNDec(state, RTKs[r-i-1])
+
+ for byte in range(0, BLOCK_BYTES):
+ state[byte] = state_output[byte]
+
+ state_output = LastRoundEGFN(state, RTKs[0])
+
+ return state_output