Skip to content

Commit

Permalink
Merge pull request #199 from Crypto-TII/fix/xor_linear_enumeration
Browse files Browse the repository at this point in the history
Fix/xor linear enumeration
  • Loading branch information
peacker authored Mar 19, 2024
2 parents 17003bc + dcf45cc commit 0c62899
Show file tree
Hide file tree
Showing 9 changed files with 208 additions and 69 deletions.
57 changes: 55 additions & 2 deletions claasp/cipher_modules/models/cp/cp_models/cp_xor_linear_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,17 @@ def find_all_xor_linear_trails_with_fixed_weight(self, fixed_weight, fixed_value
sage: trails = cp.find_all_xor_linear_trails_with_fixed_weight(1) # long
sage: len(trails)
12
# including the key schedule in the model
sage: from claasp.cipher_modules.models.cp.cp_models.cp_xor_linear_model import CpXorLinearModel
sage: from claasp.ciphers.block_ciphers.speck_block_cipher import SpeckBlockCipher
sage: from claasp.cipher_modules.models.utils import set_fixed_variables
sage: speck = SpeckBlockCipher(block_bit_size=8, key_bit_size=16, number_of_rounds=4)
sage: cp = CpXorLinearModel(speck)
sage: key = set_fixed_variables('key', 'not_equal', list(range(16)), [0] * 16)
sage: trails = cp.find_all_xor_linear_trails_with_fixed_weight(2, fixed_values=[key])
sage: len(trails)
8
"""
start = tm.time()
self.build_xor_linear_trail_model(fixed_weight, fixed_values)
Expand Down Expand Up @@ -276,6 +287,17 @@ def find_all_xor_linear_trails_with_weight_at_most(self, min_weight, max_weight=
sage: trails = cp.find_all_xor_linear_trails_with_weight_at_most(0, 1)
sage: len(trails)
13
# including the key schedule in the model
sage: from claasp.cipher_modules.models.cp.cp_models.cp_xor_linear_model import CpXorLinearModel
sage: from claasp.ciphers.block_ciphers.speck_block_cipher import SpeckBlockCipher
sage: speck = SpeckBlockCipher(block_bit_size=8, key_bit_size=16, number_of_rounds=4)
sage: cp = CpXorLinearModel(speck)
sage: from claasp.cipher_modules.models.utils import set_fixed_variables
sage: key = set_fixed_variables('key', 'not_equal', list(range(16)), [0] * 16)
sage: trails = cp.find_all_xor_linear_trails_with_weight_at_most(0, 3, fixed_values=[key])
sage: len(trails)
73
"""
start = tm.time()
self.build_xor_linear_trail_model(0, fixed_values)
Expand Down Expand Up @@ -316,7 +338,18 @@ def find_lowest_weight_xor_linear_trail(self, fixed_values=[], solver_name='Chuf
sage: cp= CpXorLinearModel(speck)
sage: trail = cp.find_lowest_weight_xor_linear_trail()
sage: trail['total_weight']
3.0
'3.0'
# including the key schedule in the model
sage: from claasp.cipher_modules.models.cp.cp_models.cp_xor_linear_model import CpXorLinearModel
sage: from claasp.ciphers.block_ciphers.speck_block_cipher import SpeckBlockCipher
sage: from claasp.cipher_modules.models.utils import set_fixed_variables
sage: speck = SpeckBlockCipher(block_bit_size=16, key_bit_size=32, number_of_rounds=4)
sage: cp = CpXorLinearModel(speck)
sage: key = set_fixed_variables('key', 'not_equal', list(range(32)), [0] * 32)
sage: trail = cp.find_lowest_weight_xor_linear_trail(fixed_values=[key])
sage: trail['total_weight']
'3.0'
"""
start = tm.time()
self.build_xor_linear_trail_model(-1, fixed_values)
Expand Down Expand Up @@ -349,6 +382,15 @@ def find_one_xor_linear_trail(self, fixed_values=[], solver_name='Chuffed'):
sage: speck = SpeckBlockCipher(block_bit_size=32, key_bit_size=64, number_of_rounds=4)
sage: cp = CpXorLinearModel(speck)
sage: cp.find_one_xor_linear_trail() # random
# including the key schedule in the model
sage: from claasp.cipher_modules.models.cp.cp_models.cp_xor_linear_model import CpXorLinearModel
sage: from claasp.ciphers.block_ciphers.speck_block_cipher import SpeckBlockCipher
sage: speck = SpeckBlockCipher(block_bit_size=32, key_bit_size=64, number_of_rounds=4)
sage: cp = CpXorLinearModel(speck)
sage: from claasp.cipher_modules.models.utils import set_fixed_variables
sage: key = set_fixed_variables('key', 'not_equal', list(range(64)), [0] * 64)
sage: cp.find_one_xor_linear_trail(fixed_values=[key]) # random
"""
start = tm.time()
self.build_xor_linear_trail_model(0, fixed_values)
Expand Down Expand Up @@ -381,7 +423,18 @@ def find_one_xor_linear_trail_with_fixed_weight(self, fixed_weight=-1, fixed_val
sage: from claasp.ciphers.block_ciphers.speck_block_cipher import SpeckBlockCipher
sage: speck = SpeckBlockCipher(block_bit_size=32, key_bit_size=64, number_of_rounds=4)
sage: cp = CpXorLinearModel(speck)
sage: trail = cp.find_one_xor_linear_trail_with_fixed_weight(3) # random
sage: trail = cp.find_one_xor_linear_trail_with_fixed_weight(3)
sage: trail['total_weight']
'3.0'
# including the key schedule in the model
sage: from claasp.cipher_modules.models.cp.cp_models.cp_xor_linear_model import CpXorLinearModel
sage: from claasp.ciphers.block_ciphers.speck_block_cipher import SpeckBlockCipher
sage: speck = SpeckBlockCipher(block_bit_size=8, key_bit_size=16, number_of_rounds=4)
sage: cp = CpXorLinearModel(speck)
sage: from claasp.cipher_modules.models.utils import set_fixed_variables
sage: key = set_fixed_variables('key', 'not_equal', list(range(16)), [0] * 16)
sage: trail = cp.find_one_xor_linear_trail_with_fixed_weight(3, fixed_values=[key])
sage: trail['total_weight']
'3.0'
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@
from claasp.cipher_modules.models.milp.milp_model import MilpModel, verbose_print
from claasp.cipher_modules.models.milp.utils.milp_name_mappings import MILP_XOR_DIFFERENTIAL, MILP_PROBABILITY_SUFFIX, \
MILP_BUILDING_MESSAGE, MILP_XOR_DIFFERENTIAL_OBJECTIVE
from claasp.cipher_modules.models.milp.utils.utils import _string_to_hex, _get_variables_values_as_string
from claasp.cipher_modules.models.milp.utils.utils import _string_to_hex, _get_variables_values_as_string, _filter_fixed_variables
from claasp.cipher_modules.models.utils import integer_to_bit_list, set_component_solution, \
get_single_key_scenario_format_for_fixed_values
from claasp.name_mappings import (CONSTANT, INTERMEDIATE_OUTPUT, CIPHER_OUTPUT,
WORD_OPERATION, LINEAR_LAYER, SBOX, MIX_COLUMN)
WORD_OPERATION, LINEAR_LAYER, SBOX, MIX_COLUMN, INPUT_KEY)


class MilpXorDifferentialModel(MilpModel):
Expand Down Expand Up @@ -148,7 +148,7 @@ def find_all_xor_differential_trails_with_fixed_weight(self, fixed_weight, fixed
EXAMPLES::
# single-key setting
from claasp.cipher_modules.models.milp.milp_models.milp_xor_differential_model import MilpXorDifferentialModel
sage: from claasp.cipher_modules.models.milp.milp_models.milp_xor_differential_model import MilpXorDifferentialModel
sage: from claasp.ciphers.block_ciphers.speck_block_cipher import SpeckBlockCipher
sage: speck = SpeckBlockCipher(number_of_rounds=5)
sage: milp = MilpXorDifferentialModel(speck)
Expand Down Expand Up @@ -184,8 +184,10 @@ def find_all_xor_differential_trails_with_fixed_weight(self, fixed_weight, fixed
end = time.time()
building_time = end - start

if fixed_values == []:
fixed_values = get_single_key_scenario_format_for_fixed_values(self._cipher)
if self.is_single_key(fixed_values):
inputs_ids = [i for i in self._cipher.inputs if "key" not in i]
inputs_ids = [i for i in self._cipher.inputs if INPUT_KEY not in i]
else:
inputs_ids = self._cipher.inputs

Expand All @@ -202,34 +204,16 @@ def find_all_xor_differential_trails_with_fixed_weight(self, fixed_weight, fixed
self._number_of_trails_found += 1
verbose_print(f"trails found : {self._number_of_trails_found}")
list_trails.append(solution)
fixed_variables = []
for index, input in enumerate(inputs_ids):
fixed_variable = {}
fixed_variable["component_id"] = input
input_bit_size = self._cipher.inputs_bit_size[index]
fixed_variable["bit_positions"] = list(range(input_bit_size))
fixed_variable["constraint_type"] = "not_equal"
fixed_variable["bit_values"] = integer_to_bit_list(
BitArray(solution["components_values"][input]["value"]).int, input_bit_size, 'big')
fixed_variables.append(fixed_variable)

for cipher_round in self._cipher.rounds_as_list:
for component in cipher_round.components:
fixed_variable = {}
fixed_variable["component_id"] = component.id
output_bit_size = component.output_bit_size
fixed_variable["bit_positions"] = list(range(output_bit_size))
fixed_variable["constraint_type"] = "not_equal"
fixed_variable["bit_values"] = integer_to_bit_list(
BitArray(solution["components_values"][component.id]["value"]).int, output_bit_size, 'big')
fixed_variables.append(fixed_variable)
fixed_variables = self._get_fixed_variables_from_solution(fixed_values, inputs_ids, solution)

fix_var_constraints = self.exclude_variables_value_constraints(fixed_variables)
number_new_constraints += len(fix_var_constraints)
for constraint in fix_var_constraints:
mip.add_constraint(constraint)
except Exception:
looking_for_other_solutions = 0
finally:
sys.stdout = sys.__stdout__

number_constraints = mip.number_of_constraints()
mip.remove_constraints(range(number_constraints - number_new_constraints, number_constraints))
Expand Down Expand Up @@ -401,7 +385,7 @@ def find_all_xor_differential_trails_with_weight_at_most(self, min_weight, max_w
fixed_values = get_single_key_scenario_format_for_fixed_values(self._cipher)
inputs_ids = self._cipher.inputs
if self.is_single_key(fixed_values):
inputs_ids = [i for i in self._cipher.inputs if "key" not in i]
inputs_ids = [i for i in self._cipher.inputs if INPUT_KEY not in i]

list_trails = []
for weight in range(min_weight, max_weight + 1):
Expand All @@ -421,15 +405,16 @@ def find_all_xor_differential_trails_with_weight_at_most(self, min_weight, max_w
self._number_of_trails_found += 1
verbose_print(f"trails found : {self._number_of_trails_found}")
list_trails.append(solution)
fixed_variables = self.get_fixed_variables_for_all_xor_differential_trails_with_weight_at_most(
fixed_values, inputs_ids, solution)
fixed_variables = self._get_fixed_variables_from_solution(fixed_values, inputs_ids, solution)

fix_var_constraints = self.exclude_variables_value_constraints(fixed_variables)
for constraint in fix_var_constraints:
mip.add_constraint(constraint)
number_new_constraints += len(fix_var_constraints)
except Exception:
looking_for_other_solutions = 0
finally:
sys.stdout = sys.__stdout__
number_constraints = mip.number_of_constraints()
mip.remove_constraints(range(number_constraints - number_new_constraints, number_constraints))
self._number_of_trails_found = 0
Expand Down Expand Up @@ -597,31 +582,29 @@ def find_one_xor_differential_trail_with_fixed_weight(self, fixed_weight, fixed_

return solution

def get_fixed_variables_for_all_xor_differential_trails_with_weight_at_most(self, fixed_values, inputs_ids,
solution):
def _get_fixed_variables_from_solution(self, fixed_values, inputs_ids, solution):
fixed_variables = []
for index, input in enumerate(inputs_ids):
input_bit_size = self._cipher.inputs_bit_size[index]
for input in inputs_ids:
input_bit_size = self._cipher.inputs_bit_size[self._cipher.inputs.index(input)]
fixed_variable = {"component_id": input,
"bit_positions": list(range(input_bit_size)),
"constraint_type": "not_equal",
"bit_values": (integer_to_bit_list(
BitArray(solution["components_values"][input]["value"]).int,
input_bit_size, 'big'))}
_filter_fixed_variables(fixed_values, fixed_variable, input)
fixed_variables.append(fixed_variable)

fixed_variables += [fixed_variable for dictio in fixed_values
if dictio["component_id"] == input and
dictio["bit_values"] != fixed_variable["bit_values"]]

for component in self._cipher.get_all_components():
output_bit_size = component.output_bit_size
fixed_variable = {"component_id": component.id,
"bit_positions": list(range(output_bit_size)),
"constraint_type": "not_equal",
"bit_values": integer_to_bit_list(
BitArray(solution["components_values"][component.id]["value"]).int,
output_bit_size, 'big')}
fixed_variables.append(fixed_variable)
for component in self._cipher.get_all_components():
output_bit_size = component.output_bit_size
fixed_variable = {"component_id": component.id,
"bit_positions": list(range(output_bit_size)),
"constraint_type": "not_equal",
"bit_values": integer_to_bit_list(
BitArray(solution["components_values"][component.id]["value"]).int,
output_bit_size, 'big')}
_filter_fixed_variables(fixed_values, fixed_variable, component.id)
fixed_variables.append(fixed_variable)

return fixed_variables

Expand Down
Loading

0 comments on commit 0c62899

Please sign in to comment.