From 557281b1e7c92663b734d60649bf30decc788d80 Mon Sep 17 00:00:00 2001 From: cs Date: Wed, 4 Sep 2024 03:16:05 +0400 Subject: [PATCH 1/7] FEATURE/Add:create uBlock cipher --- .../block_ciphers/ublock_block_cipher.py | 333 ++++++++++++++++++ 1 file changed, 333 insertions(+) create mode 100644 claasp/ciphers/block_ciphers/ublock_block_cipher.py diff --git a/claasp/ciphers/block_ciphers/ublock_block_cipher.py b/claasp/ciphers/block_ciphers/ublock_block_cipher.py new file mode 100644 index 00000000..eb9fd42c --- /dev/null +++ b/claasp/ciphers/block_ciphers/ublock_block_cipher.py @@ -0,0 +1,333 @@ + +# **************************************************************************** +# 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 . +# **************************************************************************** + + +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': 128, 'key_bit_size': 128, 'r': 16}, + {'block_bit_size': 128, 'key_bit_size': 256, 'r': 24}, + {'block_bit_size': 256, 'key_bit_size': 256, 'r': 24}, +] + +SBOX = [0x7, 0x4, 0x9, 0xc, 0xb, 0xa, 0xd, 0x8, 0xf, 0xe, 0x1, 0x6, 0x0, 0x3, 0x2, 0x5] +SBOX_TK = [0x0, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x3, 0x1, 0x7, 0x5, 0xb, 0x9, 0xf, 0xd] +SBOX_SIZE = 4 +PL = [ + [1, 3, 4, 6, 0, 2, 7, 5], + [13, 10, 3, 4, 8, 1, 15, 6, 7, 0, 14, 9, 11, 2, 12, 5] +] +PR = [ + [2, 7, 5, 0, 1, 6, 4, 3], + [6, 11, 1, 12, 9, 4, 2, 15, 7, 0, 13, 10, 14, 3, 8, 5] +] +P_WORD_SIZE = 8 +PK = [ + [6, 0, 8, 13, 1, 15, 5, 10, 4, 9, 12, 2, 11, 3, 7, 14], + [10, 5, 15, 0, 2, 7, 8, 13, 14, 6, 4, 12, 1, 3, 11, 9, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, + 23], + [10, 5, 15, 0, 2, 7, 8, 13, 14, 6, 4, 12, 1, 3, 11, 9, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, + 23] +] +PK_WORD_SIZE = 4 +RC = [ + 0x988cc9dd, 0xf0e4a1b5, 0x21357064, 0x8397d2c6, 0xc7d39682, 0x4f5b1e0a, 0x5e4a0f1b, 0x7c682d39, + 0x392d687c, 0xb3a7e2f6, 0xa7b3f6e2, 0x8e9adfcb, 0xdcc88d99, 0x786c293d, 0x30246175, 0xa1b5f0e4, + 0x8296d3c7, 0xc5d19480, 0x4a5e1b0f, 0x55410410, 0x6b7f3a2e, 0x17034652, 0xeffbbeaa, 0x1f0b4e5a, +] +RC_SIZE = 32 +ROTATE_SIZE = 32 + +class UblockBlockCipher(Cipher): + """ + Construct an instance of the UblockBlockCipher class. + + This class is used to store compact representations of a cipher, used to generate the corresponding cipher. + + INPUT: + + - ``block_bit_size`` -- **integer** (default: `128`); cipher input and output block bit size of the cipher + - ``key_bit_size`` -- **integer** (default: `128`); cipher round_key bit size of the cipher + - ``r`` -- **integer** (default: `0`); number of rounds of the cipher. The cipher uses the + corresponding amount given the other parameters (if available) when r is 0 + + EXAMPLES:: + + sage: from claasp.ciphers.block_ciphers.ublock_block_cipher import UblockBlockCipher + sage: ublock = UblockBlockCipher() + sage: ublock.r + 16 + + sage: ublock.component_from(0, 0).id + 'rot_0_0' + """ + + def __init__(self, block_bit_size=128, key_bit_size=128, number_of_rounds=0): + self.half_block_bit_size = int(block_bit_size / 2) + self.key_block_size = int(key_bit_size / 4) + self.block_bit_size = block_bit_size + self.key_bit_size = key_bit_size + self.r = number_of_rounds + + error = self.check_parameters() + if error == 1: + return + + super().__init__(family_name="ublock", + cipher_type="block_cipher", + cipher_inputs=[INPUT_PLAINTEXT, INPUT_KEY], + cipher_inputs_bit_size=[self.block_bit_size, self.key_bit_size], + cipher_output_bit_size=self.block_bit_size) + + state_left, state_right, key_0, key_1, key_2, key_3, round_key = self.round_initialization() + + for round_number in range(self.r): + self.add_round() + + # encryption + state_left, state_right = self.round_function(state_left, state_right, round_key) + # round output + self.add_round_key_output_component(round_key.id, round_key.input_bit_positions, self.block_bit_size) + if round_number < self.r-1: + self.add_round_output_component(state_left.id + state_right.id, + state_left.input_bit_positions + state_right.input_bit_positions, + block_bit_size) + # round_key schedule + key_0, key_1, key_2, key_3, round_key = self.key_schedule(key_0, key_1, key_2, key_3, round_key, RC[round_number]) + + # cipher output and round key output + self.add_XOR_component(state_left.id+state_right.id+round_key.id, + state_left.input_bit_positions+state_right.input_bit_positions+round_key.input_bit_positions, + self.block_bit_size + ) + self.add_round_key_output_component(round_key.id, round_key.input_bit_positions, self.block_bit_size) + self.add_cipher_output_component(state_left.id + state_right.id, + state_left.input_bit_positions + state_right.input_bit_positions, + block_bit_size) + def check_parameters(self): + if self.block_bit_size == 128: + self.pl = PL[0] + self.pr = PR[0] + if self.key_bit_size == 128: + self.pk = PK[0] + if self.r == 0: + self.r = 16 + elif self.key_bit_size == 256: + self.pk = PK[1] + if self.r == 0: + self.r = 24 + else: + print("The round_key size of block size 128 should be 128 or 256.") + return 1 + elif self.block_bit_size == 256: + self.pl = PL[1] + self.pr = PR[1] + if self.key_bit_size == 256: + self.pk = PK[2] + if self.r == 0: + self.r = 24 + else: + print("The round_key size of block size 256 should be 256.") + return 1 + else: + print("The block size should be 128 or 256.") + return 1 + + return 0 + + def round_initialization(self): + left_state = ComponentState([INPUT_PLAINTEXT], [list(range(self.half_block_bit_size))]) + right_state = ComponentState([INPUT_PLAINTEXT], [list(range(self.half_block_bit_size, self.block_bit_size))]) + key_0 = ComponentState([INPUT_KEY], [list(range(self.key_block_size))]) + key_1 = ComponentState([INPUT_KEY], [list(range(self.key_block_size, self.key_block_size * 2))]) + key_2 = ComponentState([INPUT_KEY], [list(range(self.key_block_size * 2, self.key_block_size * 3))]) + key_3 = ComponentState([INPUT_KEY], [list(range(self.key_block_size * 3, self.key_block_size * 4))]) + round_key = ComponentState([INPUT_KEY], [list(range(self.block_bit_size))]) + + return left_state, right_state, key_0, key_1, key_2, key_3, round_key + + def round_function(self, state_left, state_right, round_key): + + # state xor round_key + self.add_XOR_component(state_left.id+state_right.id+round_key.id, + state_left.input_bit_positions+state_right.input_bit_positions+round_key.input_bit_positions, + self.block_bit_size) + state_left = ComponentState([self.get_current_component_id()], [list(range(self.half_block_bit_size))]) + state_right = ComponentState([self.get_current_component_id()], [list(range(self.half_block_bit_size, self.block_bit_size))]) + + # sbox_n(state_left) + id = [] + window_size = SBOX_SIZE + n = int(self.half_block_bit_size / window_size) + for i in range(n): + self.add_SBOX_component(state_left.id, [list(range(i * window_size, (i + 1) * window_size))], window_size, SBOX) + id.append(self.get_current_component_id()) + state_left = ComponentState(id, [list(range(window_size))]*n) + + # sbox_n(state_right) + id = [] + window_size = SBOX_SIZE + n = int(self.half_block_bit_size / window_size) + for i in range(n): + self.add_SBOX_component(state_right.id, [list(range(i * window_size, (i + 1) * window_size))], window_size, SBOX) + id.append(self.get_current_component_id()) + state_right = ComponentState(id, [list(range(window_size))] * n) + + # state_right = state_left xor state_right + self.add_XOR_component(state_left.id+state_right.id, + state_left.input_bit_positions+state_right.input_bit_positions, + self.half_block_bit_size) + state_right = ComponentState([self.get_current_component_id()], [list(range(self.half_block_bit_size))]) + + # state_left = state_left xor (state_right <<<_32 4) + id = [] + window_size = ROTATE_SIZE + n = int(self.half_block_bit_size / window_size) + for i in range(n): + self.add_rotate_component(state_right.id, [list(range(i * window_size, (i + 1) * window_size))], window_size, 4) + id.append(self.get_current_component_id()) + temp = ComponentState(id, [list(range(window_size))] * n) + self.add_XOR_component(state_left.id + temp.id, + state_left.input_bit_positions + temp.input_bit_positions, + self.half_block_bit_size) + state_left = ComponentState([self.get_current_component_id()], [list(range(self.half_block_bit_size))]) + + # state_right = state_right xor (state_left <<<_32 8) + id = [] + window_size = ROTATE_SIZE + n = int(self.half_block_bit_size / window_size) + for i in range(n): + self.add_rotate_component(state_left.id, [list(range(i * window_size, (i + 1) * window_size))], + window_size, 8) + id.append(self.get_current_component_id()) + temp = ComponentState(id, [list(range(window_size))] * n) + self.add_XOR_component(temp.id + state_right.id, + temp.input_bit_positions + state_right.input_bit_positions, + self.half_block_bit_size) + state_right = ComponentState([self.get_current_component_id()], [list(range(self.half_block_bit_size))]) + + # state_left = state_left xor (state_right <<<_32 8) + id = [] + window_size = ROTATE_SIZE + n = int(self.half_block_bit_size / window_size) + for i in range(n): + self.add_rotate_component(state_right.id, [list(range(i * window_size, (i + 1) * window_size))], window_size, 8) + id.append(self.get_current_component_id()) + temp = ComponentState(id, [list(range(window_size))] * n) + self.add_XOR_component(state_left.id + temp.id, + state_left.input_bit_positions + temp.input_bit_positions, + self.half_block_bit_size) + state_left = ComponentState([self.get_current_component_id()], [list(range(self.half_block_bit_size))]) + + # state_right = state_right xor (state_left <<<_32 20) + id = [] + window_size = ROTATE_SIZE + n = int(self.half_block_bit_size / window_size) + for i in range(n): + self.add_rotate_component(state_left.id, [list(range(i * window_size, (i + 1) * window_size))], + window_size, 20) + id.append(self.get_current_component_id()) + temp = ComponentState(id, [list(range(window_size))] * n) + self.add_XOR_component(temp.id + state_right.id, + temp.input_bit_positions + state_right.input_bit_positions, + self.half_block_bit_size) + state_right = ComponentState([self.get_current_component_id()], [list(range(self.half_block_bit_size))]) + + # state_left = state_left xor state_right + self.add_XOR_component(state_left.id + state_right.id, + state_left.input_bit_positions + state_right.input_bit_positions, + self.half_block_bit_size) + state_left = ComponentState([self.get_current_component_id()], [list(range(self.half_block_bit_size))]) + + # state_left = PL(state_left) + self.add_word_permutation_component(state_left.id, state_left.input_bit_positions, self.half_block_bit_size, PL, P_WORD_SIZE) + state_left = ComponentState([self.get_current_component_id()], [list(range(self.half_block_bit_size))]) + + # state_right = PR(state_right) + self.add_word_permutation_component(state_right.id, state_right.input_bit_positions, self.half_block_bit_size, PR, P_WORD_SIZE) + state_right = ComponentState([self.get_current_component_id()], [list(range(self.half_block_bit_size))]) + + return state_left, state_right + + def key_schedule(self, key_0, key_1, key_2, key_3, round_key, RC): + # K0||K1 = PK(K0||K1) + self.add_word_permutation_component(key_0.id+key_1.id, + key_0.input_bit_positions+key_1.input_bit_positions, + self.key_block_size*2, + PK, PK_WORD_SIZE) + key_0 = ComponentState([self.get_current_component_id()], [list(range(self.key_block_size))]) + key_1 = ComponentState([self.get_current_component_id()], [list(range(self.key_block_size, self.key_block_size * 2))]) + + # K2 = K2 xor sbox_k(K0 xor RC) + if self.key_block_size == RC_SIZE: + self.add_XOR_component(key_0.id+RC.id, key_0.input_bit_positions+RC.input_bit_positions, RC_SIZE) + temp = ComponentState([self.get_current_component_id()], [list(range(self.key_block_size))]) + id = [] + window_size = SBOX_SIZE + n = int(self.key_block_size / window_size) + for i in range(n): + self.add_SBOX_component(temp.id, [list(range(i * window_size, (i + 1) * window_size))], + window_size, SBOX) + id.append(self.get_current_component_id()) + temp = ComponentState(id, [list(range(window_size))] * n) + else: + key_0_left = ComponentState(key_0.id, [list(range(RC_SIZE))]) + key_0_right = ComponentState(key_0.id, [list(range(RC_SIZE, self.key_block_size))]) + self.add_XOR_component(key_0_left.id + RC.id, key_0_left.input_bit_positions + RC.input_bit_positions, RC_SIZE) + temp = ComponentState([self.get_current_component_id()], [list(range(self.key_block_size))]) + id = [] + window_size = SBOX_SIZE + n = int(RC_SIZE / window_size) + for i in range(n): + self.add_SBOX_component(temp.id, [list(range(i * window_size, (i + 1) * window_size))], + window_size, SBOX) + id.append(self.get_current_component_id()) + n = int((self.key_block_size-RC_SIZE) / window_size) + for i in range(n): + self.add_SBOX_component(temp.id, [key_0_right.input_bit_positions[0][i * window_size: (i + 1) * window_size]], + window_size, SBOX) + id.append(self.get_current_component_id()) + temp = ComponentState(id, [list(range(window_size))] * n) + self.add_XOR_component(key_2.id + temp.id, key_2.input_bit_positions + temp.input_bit_positions, self.key_block_size) + key_2 = ComponentState([self.get_current_component_id()], [list(range(self.key_block_size))]) + + # K3 = K3 xor sbox_tk(K1) + id = [] + window_size = SBOX_SIZE + n = int(self.key_block_size / window_size) + for i in range(n): + self.add_SBOX_component(key_1.id, [list(range(i * window_size, (i + 1) * window_size))], + window_size, SBOX_TK) + id.append(self.get_current_component_id()) + temp = ComponentState(id, [list(range(window_size))] * n) + self.add_XOR_component(key_3.id + temp.id, key_3.input_bit_positions + temp.input_bit_positions, self.key_block_size) + key_3 = ComponentState([self.get_current_component_id()], [list(range(self.key_block_size))]) + + # K = K2 || K3 || K1 || K0 + if self.key_bit_size == self.block_bit_size: + round_key = ComponentState(key_2.id+key_3.id+key_1.id+key_0.id, + key_2.input_bit_positions+key_3.input_bit_positions+key_1.input_bit_positions+key_0.input_bit_positions) + else: + round_key = ComponentState(key_2.id+key_3.id, + key_2.input_bit_positions+key_3.input_bit_positions) + + return key_2, key_3, key_1, key_0, round_key + From 9abd814a1dbc0cd56ed325cdade3a7381393a6d1 Mon Sep 17 00:00:00 2001 From: cs Date: Wed, 4 Sep 2024 03:27:45 +0400 Subject: [PATCH 2/7] add ublock unit test --- .../block_ciphers/ublock_block_cipher_test.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tests/unit/ciphers/block_ciphers/ublock_block_cipher_test.py diff --git a/tests/unit/ciphers/block_ciphers/ublock_block_cipher_test.py b/tests/unit/ciphers/block_ciphers/ublock_block_cipher_test.py new file mode 100644 index 00000000..e9355970 --- /dev/null +++ b/tests/unit/ciphers/block_ciphers/ublock_block_cipher_test.py @@ -0,0 +1,36 @@ +from claasp.ciphers.block_ciphers.ublock_block_cipher import UblockBlockCipher + + +def test_ublock_block_cipher(): + ublock = UblockBlockCipher() + assert ublock.type == 'block_cipher' + assert ublock.family_name == 'ublock' + assert ublock.number_of_rounds == 16 + assert ublock.id == 'ublock_p128_k128_o128_r16' + assert ublock.component_from(0, 0).id == 'xor_0_0' + + ublock = UblockBlockCipher(number_of_rounds=4) + assert ublock.number_of_rounds == 4 + assert ublock.id == 'speck_p128_k128_o128_r4' + assert ublock.component_from(3, 0).id == 'xor_3_0' + + ublock = UblockBlockCipher(block_bit_size=128, key_bit_size=128) + plaintext = 0x0123456789abcdeffedcba9876543210 + key = 0x0123456789abcdeffedcba9876543210 + ciphertext = 0x32122bedd023c429023470e1158c147d + assert ublock.evaluate([plaintext, key]) == ciphertext + assert ublock.evaluate_vectorized([plaintext, key], evaluate_api=True) == ciphertext + + ublock = UblockBlockCipher(block_bit_size=128, key_bit_size=256) + plaintext = 0x0123456789abcdeffedcba9876543210 + key = 0x0123456789abcdeffedcba9876543210000102030405060708090a0b0c0d0e0f + ciphertext = 0x64accd6e34cac84d384cd4ba7aeadd19 + assert ublock.evaluate([plaintext, key]) == ciphertext + assert ublock.evaluate_vectorized([plaintext, key], evaluate_api=True) == ciphertext + + ublock = UblockBlockCipher(block_bit_size=256, key_bit_size=256) + plaintext = 0x0123456789abcdeffedcba9876543210000102030405060708090a0b0c0d0e0f + key = 0x0123456789abcdeffedcba9876543210000102030405060708090a0b0c0d0e0f + ciphertext = 0xd8e9351c5f4d27ea842135ca1640ad4b0ce119bc25c03e7c329ea8fe93e7bdfe + assert ublock.evaluate([plaintext, key]) == ciphertext + assert ublock.evaluate_vectorized([plaintext, key], evaluate_api=True) == ciphertext From 0c00a1c726f996685322e438a9fd9729df66ab99 Mon Sep 17 00:00:00 2001 From: cs Date: Wed, 4 Sep 2024 23:15:33 +0400 Subject: [PATCH 3/7] fix bugs --- .../block_ciphers/ublock_block_cipher.py | 51 ++++++++++--------- .../block_ciphers/ublock_block_cipher_test.py | 2 +- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/claasp/ciphers/block_ciphers/ublock_block_cipher.py b/claasp/ciphers/block_ciphers/ublock_block_cipher.py index eb9fd42c..b34401f7 100644 --- a/claasp/ciphers/block_ciphers/ublock_block_cipher.py +++ b/claasp/ciphers/block_ciphers/ublock_block_cipher.py @@ -73,11 +73,11 @@ class UblockBlockCipher(Cipher): sage: from claasp.ciphers.block_ciphers.ublock_block_cipher import UblockBlockCipher sage: ublock = UblockBlockCipher() - sage: ublock.r + sage: ublock.number_of_rounds 16 sage: ublock.component_from(0, 0).id - 'rot_0_0' + 'xor_0_0' """ def __init__(self, block_bit_size=128, key_bit_size=128, number_of_rounds=0): @@ -109,19 +109,19 @@ def __init__(self, block_bit_size=128, key_bit_size=128, number_of_rounds=0): if round_number < self.r-1: self.add_round_output_component(state_left.id + state_right.id, state_left.input_bit_positions + state_right.input_bit_positions, - block_bit_size) + self.block_bit_size) # round_key schedule - key_0, key_1, key_2, key_3, round_key = self.key_schedule(key_0, key_1, key_2, key_3, round_key, RC[round_number]) + key_0, key_1, key_2, key_3, round_key = self.key_schedule(key_0, key_1, key_2, key_3, RC[round_number]) # cipher output and round key output self.add_XOR_component(state_left.id+state_right.id+round_key.id, state_left.input_bit_positions+state_right.input_bit_positions+round_key.input_bit_positions, self.block_bit_size ) + cipher_output = ComponentState([self.get_current_component_id()], [list(range(self.block_bit_size))]) self.add_round_key_output_component(round_key.id, round_key.input_bit_positions, self.block_bit_size) - self.add_cipher_output_component(state_left.id + state_right.id, - state_left.input_bit_positions + state_right.input_bit_positions, - block_bit_size) + self.add_cipher_output_component(cipher_output.id, cipher_output.input_bit_positions, self.block_bit_size) + def check_parameters(self): if self.block_bit_size == 128: self.pl = PL[0] @@ -178,16 +178,16 @@ def round_function(self, state_left, state_right, round_key): window_size = SBOX_SIZE n = int(self.half_block_bit_size / window_size) for i in range(n): - self.add_SBOX_component(state_left.id, [list(range(i * window_size, (i + 1) * window_size))], window_size, SBOX) + self.add_SBOX_component(state_left.id, [state_left.input_bit_positions[0][i * window_size:(i + 1) * window_size]], window_size, SBOX) id.append(self.get_current_component_id()) - state_left = ComponentState(id, [list(range(window_size))]*n) + state_left = ComponentState(id, [list(range(window_size))] * n) # sbox_n(state_right) id = [] window_size = SBOX_SIZE n = int(self.half_block_bit_size / window_size) for i in range(n): - self.add_SBOX_component(state_right.id, [list(range(i * window_size, (i + 1) * window_size))], window_size, SBOX) + self.add_SBOX_component(state_right.id, [state_right.input_bit_positions[0][i * window_size:(i + 1) * window_size]], window_size, SBOX) id.append(self.get_current_component_id()) state_right = ComponentState(id, [list(range(window_size))] * n) @@ -202,7 +202,8 @@ def round_function(self, state_left, state_right, round_key): window_size = ROTATE_SIZE n = int(self.half_block_bit_size / window_size) for i in range(n): - self.add_rotate_component(state_right.id, [list(range(i * window_size, (i + 1) * window_size))], window_size, 4) + self.add_rotate_component(state_right.id, [list(range(i * window_size, (i + 1) * window_size))], + window_size, -4) id.append(self.get_current_component_id()) temp = ComponentState(id, [list(range(window_size))] * n) self.add_XOR_component(state_left.id + temp.id, @@ -216,7 +217,7 @@ def round_function(self, state_left, state_right, round_key): n = int(self.half_block_bit_size / window_size) for i in range(n): self.add_rotate_component(state_left.id, [list(range(i * window_size, (i + 1) * window_size))], - window_size, 8) + window_size, -8) id.append(self.get_current_component_id()) temp = ComponentState(id, [list(range(window_size))] * n) self.add_XOR_component(temp.id + state_right.id, @@ -229,7 +230,8 @@ def round_function(self, state_left, state_right, round_key): window_size = ROTATE_SIZE n = int(self.half_block_bit_size / window_size) for i in range(n): - self.add_rotate_component(state_right.id, [list(range(i * window_size, (i + 1) * window_size))], window_size, 8) + self.add_rotate_component(state_right.id, [list(range(i * window_size, (i + 1) * window_size))], + window_size, -8) id.append(self.get_current_component_id()) temp = ComponentState(id, [list(range(window_size))] * n) self.add_XOR_component(state_left.id + temp.id, @@ -243,7 +245,7 @@ def round_function(self, state_left, state_right, round_key): n = int(self.half_block_bit_size / window_size) for i in range(n): self.add_rotate_component(state_left.id, [list(range(i * window_size, (i + 1) * window_size))], - window_size, 20) + window_size, -20) id.append(self.get_current_component_id()) temp = ComponentState(id, [list(range(window_size))] * n) self.add_XOR_component(temp.id + state_right.id, @@ -258,27 +260,29 @@ def round_function(self, state_left, state_right, round_key): state_left = ComponentState([self.get_current_component_id()], [list(range(self.half_block_bit_size))]) # state_left = PL(state_left) - self.add_word_permutation_component(state_left.id, state_left.input_bit_positions, self.half_block_bit_size, PL, P_WORD_SIZE) + self.add_word_permutation_component(state_left.id, state_left.input_bit_positions, self.half_block_bit_size, self.pl, P_WORD_SIZE) state_left = ComponentState([self.get_current_component_id()], [list(range(self.half_block_bit_size))]) # state_right = PR(state_right) - self.add_word_permutation_component(state_right.id, state_right.input_bit_positions, self.half_block_bit_size, PR, P_WORD_SIZE) + self.add_word_permutation_component(state_right.id, state_right.input_bit_positions, self.half_block_bit_size, self.pr, P_WORD_SIZE) state_right = ComponentState([self.get_current_component_id()], [list(range(self.half_block_bit_size))]) return state_left, state_right - def key_schedule(self, key_0, key_1, key_2, key_3, round_key, RC): + def key_schedule(self, key_0, key_1, key_2, key_3, RC): # K0||K1 = PK(K0||K1) self.add_word_permutation_component(key_0.id+key_1.id, key_0.input_bit_positions+key_1.input_bit_positions, self.key_block_size*2, - PK, PK_WORD_SIZE) + self.pk, PK_WORD_SIZE) key_0 = ComponentState([self.get_current_component_id()], [list(range(self.key_block_size))]) key_1 = ComponentState([self.get_current_component_id()], [list(range(self.key_block_size, self.key_block_size * 2))]) # K2 = K2 xor sbox_k(K0 xor RC) + self.add_constant_component(RC_SIZE, RC) + round_constant = ComponentState([self.get_current_component_id()], [list(range(RC_SIZE))]) if self.key_block_size == RC_SIZE: - self.add_XOR_component(key_0.id+RC.id, key_0.input_bit_positions+RC.input_bit_positions, RC_SIZE) + self.add_XOR_component(key_0.id+round_constant.id, key_0.input_bit_positions+round_constant.input_bit_positions, RC_SIZE) temp = ComponentState([self.get_current_component_id()], [list(range(self.key_block_size))]) id = [] window_size = SBOX_SIZE @@ -291,7 +295,7 @@ def key_schedule(self, key_0, key_1, key_2, key_3, round_key, RC): else: key_0_left = ComponentState(key_0.id, [list(range(RC_SIZE))]) key_0_right = ComponentState(key_0.id, [list(range(RC_SIZE, self.key_block_size))]) - self.add_XOR_component(key_0_left.id + RC.id, key_0_left.input_bit_positions + RC.input_bit_positions, RC_SIZE) + self.add_XOR_component(key_0_left.id + round_constant.id, key_0_left.input_bit_positions + round_constant.input_bit_positions, RC_SIZE) temp = ComponentState([self.get_current_component_id()], [list(range(self.key_block_size))]) id = [] window_size = SBOX_SIZE @@ -302,10 +306,11 @@ def key_schedule(self, key_0, key_1, key_2, key_3, round_key, RC): id.append(self.get_current_component_id()) n = int((self.key_block_size-RC_SIZE) / window_size) for i in range(n): - self.add_SBOX_component(temp.id, [key_0_right.input_bit_positions[0][i * window_size: (i + 1) * window_size]], + self.add_SBOX_component(key_0_right.id, [key_0_right.input_bit_positions[0][i * window_size: (i + 1) * window_size]], window_size, SBOX) id.append(self.get_current_component_id()) - temp = ComponentState(id, [list(range(window_size))] * n) + temp = ComponentState(id, [list(range(window_size))] * int(self.key_block_size/window_size)) + self.add_XOR_component(key_2.id + temp.id, key_2.input_bit_positions + temp.input_bit_positions, self.key_block_size) key_2 = ComponentState([self.get_current_component_id()], [list(range(self.key_block_size))]) @@ -314,7 +319,7 @@ def key_schedule(self, key_0, key_1, key_2, key_3, round_key, RC): window_size = SBOX_SIZE n = int(self.key_block_size / window_size) for i in range(n): - self.add_SBOX_component(key_1.id, [list(range(i * window_size, (i + 1) * window_size))], + self.add_SBOX_component(key_1.id, [key_1.input_bit_positions[0][i * window_size:(i + 1) * window_size]], window_size, SBOX_TK) id.append(self.get_current_component_id()) temp = ComponentState(id, [list(range(window_size))] * n) diff --git a/tests/unit/ciphers/block_ciphers/ublock_block_cipher_test.py b/tests/unit/ciphers/block_ciphers/ublock_block_cipher_test.py index e9355970..a5ca350e 100644 --- a/tests/unit/ciphers/block_ciphers/ublock_block_cipher_test.py +++ b/tests/unit/ciphers/block_ciphers/ublock_block_cipher_test.py @@ -11,7 +11,7 @@ def test_ublock_block_cipher(): ublock = UblockBlockCipher(number_of_rounds=4) assert ublock.number_of_rounds == 4 - assert ublock.id == 'speck_p128_k128_o128_r4' + assert ublock.id == 'ublock_p128_k128_o128_r4' assert ublock.component_from(3, 0).id == 'xor_3_0' ublock = UblockBlockCipher(block_bit_size=128, key_bit_size=128) From 638df3eefe4d0bcf99de34439378a2c4ac237545 Mon Sep 17 00:00:00 2001 From: cs Date: Fri, 6 Sep 2024 17:45:01 +0400 Subject: [PATCH 4/7] fix bugs --- claasp/ciphers/block_ciphers/ublock_block_cipher.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/claasp/ciphers/block_ciphers/ublock_block_cipher.py b/claasp/ciphers/block_ciphers/ublock_block_cipher.py index b34401f7..1d4619ca 100644 --- a/claasp/ciphers/block_ciphers/ublock_block_cipher.py +++ b/claasp/ciphers/block_ciphers/ublock_block_cipher.py @@ -33,7 +33,7 @@ SBOX_SIZE = 4 PL = [ [1, 3, 4, 6, 0, 2, 7, 5], - [13, 10, 3, 4, 8, 1, 15, 6, 7, 0, 14, 9, 11, 2, 12, 5] + [2, 7, 8, 13, 3, 6, 9, 12, 1, 4, 15, 10, 14, 11, 5, 0] ] PR = [ [2, 7, 5, 0, 1, 6, 4, 3], @@ -44,7 +44,7 @@ [6, 0, 8, 13, 1, 15, 5, 10, 4, 9, 12, 2, 11, 3, 7, 14], [10, 5, 15, 0, 2, 7, 8, 13, 14, 6, 4, 12, 1, 3, 11, 9, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23], - [10, 5, 15, 0, 2, 7, 8, 13, 14, 6, 4, 12, 1, 3, 11, 9, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, + [10, 5, 15, 0, 2, 7, 8, 13, 1, 14, 4, 12, 9, 11, 3, 6, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23] ] PK_WORD_SIZE = 4 @@ -116,8 +116,7 @@ def __init__(self, block_bit_size=128, key_bit_size=128, number_of_rounds=0): # cipher output and round key output self.add_XOR_component(state_left.id+state_right.id+round_key.id, state_left.input_bit_positions+state_right.input_bit_positions+round_key.input_bit_positions, - self.block_bit_size - ) + self.block_bit_size) cipher_output = ComponentState([self.get_current_component_id()], [list(range(self.block_bit_size))]) self.add_round_key_output_component(round_key.id, round_key.input_bit_positions, self.block_bit_size) self.add_cipher_output_component(cipher_output.id, cipher_output.input_bit_positions, self.block_bit_size) @@ -296,7 +295,7 @@ def key_schedule(self, key_0, key_1, key_2, key_3, RC): key_0_left = ComponentState(key_0.id, [list(range(RC_SIZE))]) key_0_right = ComponentState(key_0.id, [list(range(RC_SIZE, self.key_block_size))]) self.add_XOR_component(key_0_left.id + round_constant.id, key_0_left.input_bit_positions + round_constant.input_bit_positions, RC_SIZE) - temp = ComponentState([self.get_current_component_id()], [list(range(self.key_block_size))]) + temp = ComponentState([self.get_current_component_id()], [list(range(RC_SIZE))]) id = [] window_size = SBOX_SIZE n = int(RC_SIZE / window_size) @@ -310,7 +309,6 @@ def key_schedule(self, key_0, key_1, key_2, key_3, RC): window_size, SBOX) id.append(self.get_current_component_id()) temp = ComponentState(id, [list(range(window_size))] * int(self.key_block_size/window_size)) - self.add_XOR_component(key_2.id + temp.id, key_2.input_bit_positions + temp.input_bit_positions, self.key_block_size) key_2 = ComponentState([self.get_current_component_id()], [list(range(self.key_block_size))]) From 4856b478de0287997147c1b14acab991bf3532b7 Mon Sep 17 00:00:00 2001 From: cs Date: Fri, 6 Sep 2024 18:37:59 +0400 Subject: [PATCH 5/7] correct the doctest --- claasp/ciphers/block_ciphers/ublock_block_cipher.py | 1 - 1 file changed, 1 deletion(-) diff --git a/claasp/ciphers/block_ciphers/ublock_block_cipher.py b/claasp/ciphers/block_ciphers/ublock_block_cipher.py index 1d4619ca..7b1e0e60 100644 --- a/claasp/ciphers/block_ciphers/ublock_block_cipher.py +++ b/claasp/ciphers/block_ciphers/ublock_block_cipher.py @@ -19,7 +19,6 @@ 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 = [ From 3214d0d9dd352221c2fd72fe30f9a03857dc1494 Mon Sep 17 00:00:00 2001 From: cs Date: Thu, 19 Sep 2024 02:20:11 +0400 Subject: [PATCH 6/7] Adding the reference and the testing vector --- .../block_ciphers/ublock_block_cipher.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/claasp/ciphers/block_ciphers/ublock_block_cipher.py b/claasp/ciphers/block_ciphers/ublock_block_cipher.py index 7b1e0e60..44feff72 100644 --- a/claasp/ciphers/block_ciphers/ublock_block_cipher.py +++ b/claasp/ciphers/block_ciphers/ublock_block_cipher.py @@ -58,8 +58,23 @@ class UblockBlockCipher(Cipher): """ Construct an instance of the UblockBlockCipher class. - - This class is used to store compact representations of a cipher, used to generate the corresponding cipher. + Reference: http://www.jcr.cacrnet.org.cn/EN/10.13868/j.cnki.jcr.000334 + + Following are some testing vectors: + 1. Ublock 128/128 + plaintext = 0x0123456789abcdeffedcba9876543210 + key = 0x0123456789abcdeffedcba9876543210 + ciphertext = 0x32122bedd023c429023470e1158c147d + + 2. Ublock 128/256 + plaintext = 0x0123456789abcdeffedcba9876543210 + key = 0x0123456789abcdeffedcba9876543210000102030405060708090a0b0c0d0e0f + ciphertext = 0x64accd6e34cac84d384cd4ba7aeadd19 + + 3. Ublock 256/256 + plaintext = 0x0123456789abcdeffedcba9876543210000102030405060708090a0b0c0d0e0f + key = 0x0123456789abcdeffedcba9876543210000102030405060708090a0b0c0d0e0f + ciphertext = 0xd8e9351c5f4d27ea842135ca1640ad4b0ce119bc25c03e7c329ea8fe93e7bdfe INPUT: From 8f4cb8606b1237b15284b774dbb28658a520a707 Mon Sep 17 00:00:00 2001 From: cs Date: Tue, 24 Sep 2024 12:57:43 +0400 Subject: [PATCH 7/7] adding evaluation example and testing vector reference --- .../block_ciphers/ublock_block_cipher.py | 6 ++++++ .../block_ciphers/ublock_block_cipher_test.py | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/claasp/ciphers/block_ciphers/ublock_block_cipher.py b/claasp/ciphers/block_ciphers/ublock_block_cipher.py index 44feff72..0cce9be2 100644 --- a/claasp/ciphers/block_ciphers/ublock_block_cipher.py +++ b/claasp/ciphers/block_ciphers/ublock_block_cipher.py @@ -92,6 +92,12 @@ class UblockBlockCipher(Cipher): sage: ublock.component_from(0, 0).id 'xor_0_0' + + sage: plaintext = 0x0123456789abcdeffedcba9876543210 + sage: key = 0x0123456789abcdeffedcba9876543210 + sage: ciphertext = 0x32122bedd023c429023470e1158c147d + sage: ublock.evaluate([plaintext, key]) == ciphertext + True """ def __init__(self, block_bit_size=128, key_bit_size=128, number_of_rounds=0): diff --git a/tests/unit/ciphers/block_ciphers/ublock_block_cipher_test.py b/tests/unit/ciphers/block_ciphers/ublock_block_cipher_test.py index a5ca350e..b1d68299 100644 --- a/tests/unit/ciphers/block_ciphers/ublock_block_cipher_test.py +++ b/tests/unit/ciphers/block_ciphers/ublock_block_cipher_test.py @@ -1,6 +1,24 @@ from claasp.ciphers.block_ciphers.ublock_block_cipher import UblockBlockCipher +""" +Following are some testing vectors: +1. Ublock 128/128 +plaintext = 0x0123456789abcdeffedcba9876543210 +key = 0x0123456789abcdeffedcba9876543210 +ciphertext = 0x32122bedd023c429023470e1158c147d +2. Ublock 128/256 +plaintext = 0x0123456789abcdeffedcba9876543210 +key = 0x0123456789abcdeffedcba9876543210000102030405060708090a0b0c0d0e0f +ciphertext = 0x64accd6e34cac84d384cd4ba7aeadd19 + +3. Ublock 256/256 +plaintext = 0x0123456789abcdeffedcba9876543210000102030405060708090a0b0c0d0e0f +key = 0x0123456789abcdeffedcba9876543210000102030405060708090a0b0c0d0e0f +ciphertext = 0xd8e9351c5f4d27ea842135ca1640ad4b0ce119bc25c03e7c329ea8fe93e7bdfe + +Reference: http://www.jcr.cacrnet.org.cn/EN/10.13868/j.cnki.jcr.000334 +""" def test_ublock_block_cipher(): ublock = UblockBlockCipher() assert ublock.type == 'block_cipher'