Skip to content

Commit

Permalink
Merge pull request #260 from Crypto-TII/feat/create_toy_cipher_FOUR
Browse files Browse the repository at this point in the history
Feat/create toy cipher four
  • Loading branch information
peacker authored Aug 7, 2024
2 parents 2fe0cf0 + e0402ac commit 9b37e6c
Show file tree
Hide file tree
Showing 3 changed files with 289 additions and 0 deletions.
162 changes: 162 additions & 0 deletions claasp/ciphers/toys/toy_cipherFOUR.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# ****************************************************************************
# Copyright 2023 Technology Innovation Institute
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# ****************************************************************************

from claasp.cipher import Cipher
from claasp.DTOs.component_state import ComponentState
from claasp.utils.utils import get_number_of_rounds_from
from claasp.name_mappings import INPUT_PLAINTEXT, INPUT_KEY

PARAMETERS_CONFIGURATION_LIST = [
{'block_bit_size': 16, 'key_bit_size': 96, 'number_of_rounds': 5}
]


class ToyCipherFOUR(Cipher):
"""
Construct an instance of the ToyCipherFOUR class.
This class implements CipherFOUR [Knudsen2011TheBC]_,
with a default block size of 16 bits and a key size of 96 bits.
This toy block cipher splits the key into multiple round keys.
REFERENCES:
Knudsen, L. R., & Robshaw, M. J. B. (2011). *The Block Cipher Companion*. Springer [Knudsen2011TheBC]_.
INPUT:
- ``block_bit_size`` -- **integer** (default: `16`); cipher input and output block bit size of the cipher
- ``key_bit_size`` -- **integer** (default: `80`); cipher key bit size of the cipher
- ``sbox`` -- **integer list** (default: [12, 5, 6, 11, 9, 0, 10, 13, 3, 14, 15, 8, 4, 7, 1, 2]); lookup table of the S-box.
- ``permutations`` -- **integer list** (default: [0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15])
- ``number_of_rounds`` -- **integer** (default: `5`); number of rounds of the cipher.
EXAMPLES::
sage: from claasp.ciphers.toys.toy_cipherFOUR import ToyCipherFOUR
sage: toy_cipher = ToyCipherFOUR()
sage: plaintext = 0x1234; key = 0x111122223333444455556666
sage: toy_cipher.evaluate([plaintext, key])
17897
sage: hex(toy_cipher.evaluate([plaintext, key]))
'0x45e9'
sage: toy_cipher.number_of_rounds
5
sage: toy_cipher = ToyCipherFOUR(block_bit_size=16, key_bit_size=80, number_of_rounds=10)
sage: plaintext = 0x5678; key = 0x123456781234567812abcdef
sage: hex(toy_cipher.evaluate([plaintext, key]))
'0xbeec'
sage: toy_cipher = ToyCipherFOUR(block_bit_size=16, key_bit_size=80, sbox=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0], permutations=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], number_of_rounds=5)
sage: plaintext = 0x9abc; key = 0x3333555577779999bbbbcccc
sage: hex(toy_cipher.evaluate([plaintext, key]))
'0xef01'
sage: toy_cipher.evaluate([plaintext, key])
61185
"""

def __init__(self,
block_bit_size=16,
key_bit_size=16,
rotation_layer=1,
sbox=[12, 5, 6, 11, 9, 0, 10, 13, 3, 14, 15, 8, 4, 7, 1, 2],
permutations=[0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15],
number_of_rounds=5):
self.sbox_bit_size = len(bin(len(sbox))) - 3
self.number_of_sboxes = block_bit_size // self.sbox_bit_size
self._num_rounds = number_of_rounds
self.block_bit_size = block_bit_size
self.rotation_layer = rotation_layer
self.sbox = sbox
self.permutations = permutations
super().__init__(family_name="toyspn1",
cipher_type="block_cipher",
cipher_inputs=[INPUT_PLAINTEXT, INPUT_KEY],
cipher_inputs_bit_size=[block_bit_size, key_bit_size * (number_of_rounds + 1)],
cipher_output_bit_size=block_bit_size)

state = INPUT_PLAINTEXT
key= INPUT_KEY

for round_idx in range(number_of_rounds - 1):
# XOR with round key
self.add_round()
xor = self.add_XOR_component(
[state, key],
[[i for i in range(block_bit_size)],
[i for i in range(round_idx*block_bit_size, (round_idx+1)*block_bit_size)]],
block_bit_size)
state = xor.id # Update state to XOR output

# S-box layer
sbox_outputs = []
for ns in range(self.number_of_sboxes):
sbox_component = self.add_SBOX_component(
[state],
[[ns * self.sbox_bit_size + i for i in range(self.sbox_bit_size)]],
self.sbox_bit_size,
self.sbox)
sbox_outputs.append(sbox_component.id)

# Permutation layer
state = self.permutation_layer(sbox_outputs)

self.add_round_output_component([state],
[[i for i in range(block_bit_size)]],
block_bit_size)

self.add_round()

# XOR with round key
xor = self.add_XOR_component(
[state, key],
[[i for i in range(block_bit_size)],
[i for i in range(4*block_bit_size, 5*block_bit_size)]],
block_bit_size)
state = xor.id

# Last round does not include permutation
sbox_outputs = []
for ns in range(self.number_of_sboxes):
sbox_component = self.add_SBOX_component(
[state],
[[ns * self.sbox_bit_size + i for i in range(self.sbox_bit_size)]],
self.sbox_bit_size,
self.sbox)
sbox_outputs.append(sbox_component.id)

# Final XOR with the last round key
xor = self.add_XOR_component(
[sbox_outputs[0]] + [sbox_outputs[1]] + [sbox_outputs[2]] + [sbox_outputs[3]]+[key],
[list(range(4))]*4 + [[i for i in range(5*block_bit_size, 6*block_bit_size)]],
block_bit_size)
state = xor.id

self.add_cipher_output_component(
[state],
[[i for i in range(block_bit_size)]],
block_bit_size)

def permutation_layer(self, sbox_output):
perm = self.add_permutation_component(
[sbox_output[0]] + [sbox_output[1]] + [sbox_output[2]] + [sbox_output[3]],
[list(range(4))]*4,
self.block_bit_size,
self.permutations)
return perm.id
6 changes: 6 additions & 0 deletions docs/references.rst
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,12 @@
signature schemes* : In Advances in Cryptology EUROCRYPT99, pages
206–222, Berlin, Heidelberg, 1999. Springer BerlinHeidelberg.
.. [Knudsen2011TheBC]
Knudsen, L. R., & Robshaw, M. J. B., : *The Block Cipher Companion* :
Information Security and Cryptography, 2011.
https://link.springer.com/book/10.1007/978-3-642-17342-4
.. _claasp-ref-L:

.. only:: html
Expand Down
121 changes: 121 additions & 0 deletions tests/unit/ciphers/toys/toy_cipherFOUR_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import sys
from io import StringIO

from claasp.ciphers.toys.toy_cipherFOUR import ToyCipherFOUR

def test_toycipherFOUR():
toy_cipher = ToyCipherFOUR()
assert toy_cipher.number_of_rounds == 5

plaintext = 0x1234
key = 0x111122223333444455556666
assert toy_cipher.evaluate([plaintext, key]) == 17897
assert hex(toy_cipher.evaluate([plaintext, key])) == '0x45e9'

expected_evaluation = """
Round_0
xor_0_0_input = 0x12341111
xor_0_0_output = 0x0325
sbox_0_1_input = 0x0
sbox_0_1_output = 0xc
sbox_0_2_input = 0x3
sbox_0_2_output = 0xb
sbox_0_3_input = 0x2
sbox_0_3_output = 0x6
sbox_0_4_input = 0x5
sbox_0_4_output = 0x0
linear_layer_0_5_input = 0xcb60
linear_layer_0_5_output = 0xca64
intermediate_output_0_6_input = 0xca64
intermediate_output_0_6_output = 0xca64
Round_1
xor_1_0_input = 0xca642222
xor_1_0_output = 0xe846
sbox_1_1_input = 0xe
sbox_1_1_output = 0x1
sbox_1_2_input = 0x8
sbox_1_2_output = 0x3
sbox_1_3_input = 0x4
sbox_1_3_output = 0x9
sbox_1_4_input = 0x6
sbox_1_4_output = 0xa
linear_layer_1_5_input = 0x139a
linear_layer_1_5_output = 0x305e
intermediate_output_1_6_input = 0x305e
intermediate_output_1_6_output = 0x305e
Round_2
xor_2_0_input = 0x305e3333
xor_2_0_output = 0x036d
sbox_2_1_input = 0x0
sbox_2_1_output = 0xc
sbox_2_2_input = 0x3
sbox_2_2_output = 0xb
sbox_2_3_input = 0x6
sbox_2_3_output = 0xa
sbox_2_4_input = 0xd
sbox_2_4_output = 0x7
linear_layer_2_5_input = 0xcba7
linear_layer_2_5_output = 0xe975
intermediate_output_2_6_input = 0xe975
intermediate_output_2_6_output = 0xe975
Round_3
xor_3_0_input = 0xe9754444
xor_3_0_output = 0xad31
sbox_3_1_input = 0xa
sbox_3_1_output = 0xf
sbox_3_2_input = 0xd
sbox_3_2_output = 0x7
sbox_3_3_input = 0x3
sbox_3_3_output = 0xb
sbox_3_4_input = 0x1
sbox_3_4_output = 0x5
linear_layer_3_5_input = 0xf7b5
linear_layer_3_5_output = 0xadef
intermediate_output_3_6_input = 0xadef
intermediate_output_3_6_output = 0xadef
Round_4
xor_4_0_input = 0xadef5555
xor_4_0_output = 0xf8ba
sbox_4_1_input = 0xf
sbox_4_1_output = 0x2
sbox_4_2_input = 0x8
sbox_4_2_output = 0x3
sbox_4_3_input = 0xb
sbox_4_3_output = 0x8
sbox_4_4_input = 0xa
sbox_4_4_output = 0xf
xor_4_5_input = 0x238f6666
xor_4_5_output = 0x45e9
cipher_output_4_6_input = 0x45e9
cipher_output_4_6_output = 0x45e9
"""

old_stdout = sys.stdout
result = StringIO()
sys.stdout = result
evaluation = hex(toy_cipher.evaluate([0x1234, 0x111122223333444455556666], verbosity=True))
sys.stdout = old_stdout
assert evaluation == '0x45e9'
assert result.getvalue() == expected_evaluation

toy_cipher = ToyCipherFOUR(block_bit_size=16, key_bit_size=80, number_of_rounds=10)
assert hex(toy_cipher.evaluate([0x5678, 0x22224444666688889999aaaa])) == '0xbeec'

toy_cipher = ToyCipherFOUR(block_bit_size=16, key_bit_size=80,
sbox=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0],
permutations=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
number_of_rounds=5)
assert toy_cipher.evaluate([0x9abc, 0x3333555577779999bbbbcccc]) == 61185




0 comments on commit 9b37e6c

Please sign in to comment.