diff --git a/claasp/cipher.py b/claasp/cipher.py index 96b54a39..2a6f5635 100644 --- a/claasp/cipher.py +++ b/claasp/cipher.py @@ -39,6 +39,8 @@ class Cipher: + + def __init__(self, family_name, cipher_type, cipher_inputs, cipher_inputs_bit_size, cipher_output_bit_size, cipher_reference_code=None): @@ -146,6 +148,8 @@ def __init__(self, family_name, cipher_type, cipher_inputs, self._id = self.make_cipher_id() self._file_name = self.make_file_name() + def __repr__(self): + return self.id def _are_there_not_forbidden_components(self, forbidden_types, forbidden_descriptions): return self._rounds.are_there_not_forbidden_components(forbidden_types, forbidden_descriptions) diff --git a/claasp/cipher_modules/algebraic_tests.py b/claasp/cipher_modules/algebraic_tests.py index d8a25c81..6a68f327 100644 --- a/claasp/cipher_modules/algebraic_tests.py +++ b/claasp/cipher_modules/algebraic_tests.py @@ -66,24 +66,21 @@ def algebraic_tests(self, timeout=60): nmonomials_up_to_round.append(Fseq.nmonomials()) max_deg_of_equations_up_to_round.append(Fseq.maximal_degree()) - if tests_up_to_round and tests_up_to_round[-1] is True: - tests_up_to_round.append(True) - else: - from cysignals.alarm import alarm, cancel_alarm + from cysignals.alarm import alarm, cancel_alarm, AlarmInterrupt + try: + alarm(timeout) + Fseq.groebner_basis() + cancel_alarm() + result = False + except AlarmInterrupt: + result = True - try: - alarm(timeout) - cancel_alarm() - result = False - except InterruptedError: - result = True - - tests_up_to_round.append(result) + tests_up_to_round.append(result) input_parameters = { - "cipher.id": self._cipher.id, "timeout": timeout, - "test_name": "algebraic_tests" + "test_name": "algebraic_tests", + "cipher": self._cipher } test_results = { "number_of_variables": nvars_up_to_round, diff --git a/claasp/cipher_modules/avalanche_tests.py b/claasp/cipher_modules/avalanche_tests.py index b6e85e8b..48ac4f79 100644 --- a/claasp/cipher_modules/avalanche_tests.py +++ b/claasp/cipher_modules/avalanche_tests.py @@ -87,6 +87,7 @@ def avalanche_tests(self, number_of_samples=5, avalanche_dependence_uniform_bias avalanche_dependence_uniform_bias) intermediate_output_names = self._add_intermediate_output_components_id_to_dictionary(self._cipher.get_all_components()) diffusion_tests = {"input_parameters": { + "cipher": self._cipher, "test_name": "avalanche_tests", "number_of_samples": number_of_samples, "avalanche_dependence_uniform_bias": avalanche_dependence_uniform_bias, diff --git a/claasp/cipher_modules/component_analysis_tests.py b/claasp/cipher_modules/component_analysis_tests.py index e525cc0c..24db9c39 100644 --- a/claasp/cipher_modules/component_analysis_tests.py +++ b/claasp/cipher_modules/component_analysis_tests.py @@ -69,7 +69,8 @@ def component_analysis_tests(self): output_dictionary = { 'input_parameters': { - 'test_name': 'component_analysis' + 'test_name': 'component_analysis', + 'cipher': self._cipher }, 'test_results': components_analysis } @@ -153,15 +154,19 @@ def print_component_analysis_as_radar_charts(self, results=None): plt.rcParams['figure.figsize'] = [20, 20] # remove XOR from results - results_without_xor = [results[i] for i in range(len(results)) if results[i]["description"][0] != "XOR"] - results = self._remove_components_with_strings_as_values(results_without_xor) + # results_without_xor = [results[i] for i in range(len(results)) if results[i]["description"][0] != "XOR"] + results_without_fsr = [results[i] for i in range(len(results)) if results[i]["type"] != "fsr"] + # removed for now because the fsr dictionary does not follow the standard structure as the other components: + # the keys properties, values, etc are not present. + # results = self._remove_components_with_strings_as_values(results_without_xor) + results = self._remove_components_with_strings_as_values(results_without_fsr) nb_plots = len(results) col = 2 row = nb_plots // col if nb_plots % col != 0: row += nb_plots % col - positions = {8: -0.7, 3: -0.4} + positions = {8: -0.7, 3: -0.4} # positions of the text according to the numbers of properties for plot_number in range(nb_plots): categories = list(results[plot_number]["properties"].keys()) @@ -211,10 +216,12 @@ def print_component_analysis_as_radar_charts(self, results=None): self._fill_area(ax, categories, plot_number, positions, results) # Show the graph - plt.subplots_adjust(left=0.25, bottom=0.1, right=0.7, top=0.95, wspace=0, hspace=0.96) + if nb_plots >= 5: + plt.subplots_adjust(left=0.02, bottom=0.1, right=0.7, top=0.95, wspace=1, hspace=0.96) + else: + plt.subplots_adjust(left=0.09, bottom=0.3, right=0.7, top=0.7, wspace=1, hspace=0.96) plt.show() #print("The radar chart can be plot with the build-in method plt.show()") - #return plt @@ -274,7 +281,7 @@ def _select_boolean_function(self, component, boolean_polynomial_ring): elif component.description[0] == "MODADD": return self._MODADD_as_boolean_function(component, boolean_polynomial_ring) else: - return "TODO(...)" + return f"TODO: {component.id} not implemented yet" def _MODADD_as_boolean_function(self, component, boolean_polynomial_ring): @@ -425,11 +432,8 @@ def _select_properties_function(self, boolean_polynomial_ring, operation): if component.type == 'fsr': return self._fsr_properties(operation) - if component.type == WORD_OPERATION: - print(f"TODO : {component.description[0]}") - return {} else: - print(f"TODO : {component.type}") + # print(f"TODO: not implemented yet") return {} def _is_mds(self, component): @@ -485,7 +489,6 @@ def _word_operation_properties(self, operation, boolean_polynomial_ring): INPUT: - ``operation`` -- **list**; a list containing: - * a component with the operation under study * number of occurrences of the operation * list of ids of all the components with the same underlying operation @@ -642,7 +645,7 @@ def _linear_layer_properties(self, operation): "min_possible_value": 1, "max_possible_value": pow(2, component.input_bit_size) - 1 } - if component.input_bit_size <= 32: + if component.input_bit_size <= 64: dictio["properties"]["differential_branch_number"] = {"value": branch_number(component, 'differential', 'bit'), "min_possible_value": 0, "max_possible_value": component.input_bit_size} @@ -883,7 +886,8 @@ def _fill_area(self, ax, categories, plot_number, positions, results): text += f"{category} = {int(results[plot_number]['properties'][category]['value'])} " \ f"(best is {results[plot_number]['properties'][category]['max_possible_value']}, " \ f"worst is {results[plot_number]['properties'][category]['min_possible_value']})\n" - plt.text(0, positions[len(categories)], text, transform=ax.transAxes, size="small") + # plt.text(0, positions[len(categories)], text, transform=ax.transAxes, size="small") + plt.text(2, 0, text, transform=ax.transAxes, size="small") def _initialise_spider_plot(self, plot_number, results): is_component_word_operation = results[plot_number]["type"] == "word_operation" diff --git a/claasp/cipher_modules/continuous_diffusion_analysis.py b/claasp/cipher_modules/continuous_diffusion_analysis.py index aed05b60..74f9926a 100644 --- a/claasp/cipher_modules/continuous_diffusion_analysis.py +++ b/claasp/cipher_modules/continuous_diffusion_analysis.py @@ -440,6 +440,7 @@ def continuous_diffusion_tests(self, """ continuous_diffusion_tests = {"input_parameters": { 'test_name': 'continuous_diffusion_tests', + 'cipher': self.cipher, 'continuous_avalanche_factor_number_of_samples': continuous_avalanche_factor_number_of_samples, 'threshold_for_avalanche_factor': threshold_for_avalanche_factor, 'continuous_neutral_measure_beta_number_of_samples': continuous_neutral_measure_beta_number_of_samples, diff --git a/claasp/cipher_modules/models/algebraic/algebraic_model.py b/claasp/cipher_modules/models/algebraic/algebraic_model.py index 97d97e19..629a6ab3 100644 --- a/claasp/cipher_modules/models/algebraic/algebraic_model.py +++ b/claasp/cipher_modules/models/algebraic/algebraic_model.py @@ -200,11 +200,15 @@ def polynomial_system_at_round(self, r): component_type = component.type operation = component.description[0] component_types = ["sbox", "linear_layer", "mix_column", "constant"] - operations = ["XOR", "AND", "OR", "SHIFT", "ROTATE", "NOT"] + operations = ["XOR", "AND", "OR", "SHIFT", "ROTATE", "NOT", "MODADD"] if component_type in component_types or (component_type == "word_operation" and operation in operations): polynomials += component.algebraic_polynomials(self) + elif component_type == "word_operation" and \ + operation in ['ROTATE_BY_VARIABLE_AMOUNT', 'SHIFT_BY_VARIABLE_AMOUNT', 'MODSUB']: + raise ValueError(f"polynomial generation of {operation} operation is not supported at present") + return Sequence(polynomials) def ring(self): diff --git a/claasp/cipher_modules/models/cp/cp_model.py b/claasp/cipher_modules/models/cp/cp_model.py index de8ed203..2b2e9fef 100644 --- a/claasp/cipher_modules/models/cp/cp_model.py +++ b/claasp/cipher_modules/models/cp/cp_model.py @@ -65,7 +65,7 @@ def add_solutions_from_components_values(self, components_values, memory, model_ solver_name, solver_output, total_weight): for i in range(len(total_weight)): solution = convert_solver_solution_to_dictionary( - self.cipher_id, + self._cipher, model_type, solver_name, solve_time, @@ -458,7 +458,7 @@ def solve(self, model_type, solver_name=None): solver_output = solver_process.stdout.splitlines() solve_time, memory, components_values, total_weight = self._parse_solver_output(solver_output) if components_values == {}: - solution = convert_solver_solution_to_dictionary(self.cipher_id, model_type, solver_name, + solution = convert_solver_solution_to_dictionary(self._cipher, model_type, solver_name, solve_time, memory, components_values, total_weight) if 'UNSATISFIABLE' in solver_output[0]: diff --git a/claasp/cipher_modules/models/cp/cp_models/cp_xor_differential_model.py b/claasp/cipher_modules/models/cp/cp_models/cp_xor_differential_model.py index e9228ce1..927a2817 100644 --- a/claasp/cipher_modules/models/cp/cp_models/cp_xor_differential_model.py +++ b/claasp/cipher_modules/models/cp/cp_models/cp_xor_differential_model.py @@ -355,7 +355,6 @@ def find_lowest_weight_xor_differential_trail(self, fixed_values=[], solver_name solution = self.solve('xor_differential_one_solution', solver_name) solution['building_time_seconds'] = build_time solution['test_name'] = "find_lowest_weight_xor_differential_trail" - return solution def find_one_xor_differential_trail(self, fixed_values=[], solver_name='Chuffed'): diff --git a/claasp/cipher_modules/models/milp/milp_model.py b/claasp/cipher_modules/models/milp/milp_model.py index 467aed6a..f43e35c6 100644 --- a/claasp/cipher_modules/models/milp/milp_model.py +++ b/claasp/cipher_modules/models/milp/milp_model.py @@ -344,7 +344,7 @@ def solve(self, model_type, solver_name=SOLVER_DEFAULT, external_solver_name=Non status, milp_time, milp_memory = self._solve_with_internal_solver() objective_value, components_values = self._parse_solver_output() - solution = convert_solver_solution_to_dictionary(self.cipher_id, model_type, solver_name_in_solution, milp_time, + solution = convert_solver_solution_to_dictionary(self._cipher, model_type, solver_name_in_solution, milp_time, milp_memory, components_values, objective_value) solution['status'] = status return solution diff --git a/claasp/cipher_modules/models/sat/sat_model.py b/claasp/cipher_modules/models/sat/sat_model.py index c32fbd2e..e642ac16 100644 --- a/claasp/cipher_modules/models/sat/sat_model.py +++ b/claasp/cipher_modules/models/sat/sat_model.py @@ -335,7 +335,7 @@ def _solve_with_external_sat_solver(self, model_type, solver_name, options, host component2fields, total_weight = {}, None if total_weight is not None: total_weight = float(total_weight) - solution = convert_solver_solution_to_dictionary(self.cipher_id, model_type, solver_name, sat_time, + solution = convert_solver_solution_to_dictionary(self._cipher, model_type, solver_name, sat_time, sat_memory, component2fields, total_weight) solution['status'] = status @@ -361,7 +361,7 @@ def _solve_with_sage_sat_solver(self, model_type, solver_name): status = 'UNSATISFIABLE' if total_weight is not None: total_weight = float(total_weight) - solution = convert_solver_solution_to_dictionary(self.cipher_id, model_type, solver_name, sat_time, + solution = convert_solver_solution_to_dictionary(self._cipher, model_type, solver_name, sat_time, sat_memory, component2fields, total_weight) solution['status'] = status diff --git a/claasp/cipher_modules/models/smt/smt_model.py b/claasp/cipher_modules/models/smt/smt_model.py index 17c7831b..4c898b63 100644 --- a/claasp/cipher_modules/models/smt/smt_model.py +++ b/claasp/cipher_modules/models/smt/smt_model.py @@ -434,7 +434,7 @@ def _get_data(data_string, lines): if total_weight is not None: total_weight = float(total_weight) - solution = convert_solver_solution_to_dictionary(self.cipher_id, model_type, solver_name, solve_time, + solution = convert_solver_solution_to_dictionary(self._cipher, model_type, solver_name, solve_time, memory, component2attributes, total_weight) solution['status'] = status diff --git a/claasp/cipher_modules/models/utils.py b/claasp/cipher_modules/models/utils.py index 9b57ce12..e3de94bd 100644 --- a/claasp/cipher_modules/models/utils.py +++ b/claasp/cipher_modules/models/utils.py @@ -37,7 +37,7 @@ def add_arcs(arcs, component, curr_input_bit_ids, input_bit_size, intermediate_o arcs[previous_output_bit_ids[i]].append(curr_input_bit_ids[i]) -def convert_solver_solution_to_dictionary(cipher_id, model_type, solver_name, solve_time, memory, +def convert_solver_solution_to_dictionary(cipher, model_type, solver_name, solve_time, memory, components_values, total_weight): """ Return a dictionary that represents the solution obtained from the solver. @@ -72,7 +72,7 @@ def convert_solver_solution_to_dictionary(cipher_id, model_type, solver_name, so 'total_weight': 0} """ return { - 'cipher_id': cipher_id, + 'cipher': cipher, 'model_type': model_type, 'solver_name': solver_name, 'solving_time_seconds': solve_time, diff --git a/claasp/cipher_modules/neural_network_tests.py b/claasp/cipher_modules/neural_network_tests.py index 61a4d9e8..e5793ee4 100644 --- a/claasp/cipher_modules/neural_network_tests.py +++ b/claasp/cipher_modules/neural_network_tests.py @@ -64,6 +64,7 @@ def neural_network_blackbox_distinguisher_tests(self, nb_samples=10000, """ results = {"input_parameters": { "test_name": "neural_network_blackbox_distinguisher_tests", + "cipher": self.cipher, "number_of_samples": nb_samples, "hidden_layers": hidden_layers, "number_of_epochs": number_of_epochs}, "test_results": {}} @@ -146,7 +147,7 @@ def _update_blackbox_distinguisher_vectorized_tests_ds(self, base_inputs, base_o # cipher_output = base_output base_inputs_np = [np.broadcast_to( - np.array([b for b in x.to_bytes(input_lengths[i] // 8, byteorder='big')], dtype=np.uint8), + np.array([b for b in int(x).to_bytes(input_lengths[i] // 8, byteorder='big')], dtype=np.uint8), (nb_samples, input_lengths[i] // 8) ).transpose().copy() for i, x in enumerate(base_inputs)] random_inputs_for_index = np.frombuffer(os.urandom(nb_samples * input_lengths[index] // 8), @@ -255,6 +256,7 @@ def neural_network_differential_distinguisher_tests(self, nb_samples=10000, hidd """ results = {"input_parameters": { "test_name": "neural_network_differential_distinguisher_tests", + "cipher":self.cipher, "number_of_samples": nb_samples, "input_differences": diff, "hidden_layers": hidden_layers, @@ -313,7 +315,7 @@ def _update_distinguisher_vectorized_tests_ds(self, base_inputs, d, ds, index, l random_labels_size = nb_samples - np.count_nonzero(np.array(labels)) base_inputs_np = [np.broadcast_to( - np.array([b for b in x.to_bytes(input_lengths[i] // 8, byteorder='big')], dtype=np.uint8), + np.array([b for b in int(x).to_bytes(input_lengths[i] // 8, byteorder='big')], dtype=np.uint8), (nb_samples, input_lengths[i] // 8) ).transpose().copy() for i, x in enumerate(base_inputs)] random_inputs_for_index = np.frombuffer(os.urandom(nb_samples * input_lengths[index] // 8), @@ -323,7 +325,7 @@ def _update_distinguisher_vectorized_tests_ds(self, base_inputs, d, ds, index, l other_inputs_np = list(base_inputs_np) - d_array = np.array([b for b in d.to_bytes(input_lengths[index] // 8, byteorder='big')]) + d_array = np.array([b for b in int(d).to_bytes(input_lengths[index] // 8, byteorder='big')]) other_inputs_np[index] = other_inputs_np[index] ^ np.broadcast_to(d_array, ( nb_samples, input_lengths[index] // 8)).transpose() @@ -598,6 +600,7 @@ def run_autond_pipeline(self, difference_positions=None, optimizer_samples=10 ** neural_distinguisher_test_results = { 'input_parameters': { 'test_name': 'neural_distinguisher_test', + 'cipher': self.cipher, 'optimizer_samples': optimizer_samples, 'optimizer_generations': optimizer_generations, 'training_samples': training_samples, @@ -636,6 +639,9 @@ def data_generator(nr, samples): input_size = self.cipher.output_bit_size * 2 neural_network = self.get_neural_network(neural_net, input_size = input_size) nr = max(1, highest_round-3) + + neural_distinguisher_test_results['test_results']['round_start']=nr + print(f'Training {neural_net} on input difference {[hex(x) for x in input_difference]} ({self.cipher.inputs}), from round {nr}...') neural_results = self.train_neural_distinguisher(data_generator, nr, neural_network, training_samples, testing_samples, number_of_epochs) diff --git a/claasp/cipher_modules/report.py b/claasp/cipher_modules/report.py index 3e7cbdca..b933437d 100644 --- a/claasp/cipher_modules/report.py +++ b/claasp/cipher_modules/report.py @@ -7,7 +7,7 @@ import json import shutil from claasp.cipher_modules.statistical_tests.dieharder_statistical_tests import DieharderTests -from claasp.cipher_modules.statistical_tests.nist_statistical_tests import StatisticalTests +from claasp.cipher_modules.statistical_tests.nist_statistical_tests import NISTStatisticalTests from claasp.cipher_modules.component_analysis_tests import CipherComponentsAnalysis def _print_colored_state(state, verbose, file): @@ -100,7 +100,7 @@ def _latex_heatmap(table, table_string, bit_count): class Report: - def __init__(self, cipher, test_report): + def __init__(self, test_report): """ Construct an instance of the Report class. @@ -134,7 +134,10 @@ def __init__(self, cipher, test_report): """ - self.cipher = cipher + try: + self.cipher = test_report['input_parameters']['cipher'] + except KeyError: + self.cipher = test_report['cipher'] self.test_report = test_report if 'test_name' in test_report.keys(): @@ -148,7 +151,7 @@ def __init__(self, cipher, test_report): self.input_parameters = {} self.test_name = test_report['test_name'] if type(test_report) is dict else test_report[0]['test_name'] - def show(self, test_name='trail_search', fixed_input='plaintext', fixed_output='round_output', + def show(self, test_name=None, fixed_input='plaintext', fixed_output='round_output', fixed_input_difference='average', word_size=1, state_size=1, key_state_size=1, verbose=False, show_word_permutation=False, show_var_shift=False, show_var_rotate=False, show_theta_xoodoo=False, @@ -172,23 +175,32 @@ def show(self, test_name='trail_search', fixed_input='plaintext', fixed_output=' show_and, show_or, show_not, show_plaintext, show_key, show_intermediate_output, show_cipher_output, show_input, show_output, save_fig=False) - - else: - - test_list = [] - if 'statistical' in self.test_name: - test_list.append(self.test_name) - elif 'component_analysis' in self.test_name: - Component_Analysis=CipherComponentsAnalysis(self.cipher) - Component_Analysis.print_component_analysis_as_radar_charts(results=self.test_report['test_results']) - elif 'algebraic' not in self.test_name and self.test_name !='neural_distinguisher_test': - test_list = list(self.test_report['test_results'][fixed_input][fixed_output].keys()) - if test_name not in test_list and 'algebraic' not in self.test_name and self.test_name !='neural_distinguisher_test': - print('Error! Invalid test name. Please choose a valid test name') - print('The test name has to be one of the following : ',end='') + return + elif 'component_analysis' in self.test_name: + Component_Analysis=CipherComponentsAnalysis(self.cipher) + Component_Analysis.print_component_analysis_as_radar_charts(results=self.test_report['test_results']) + return + elif 'avalanche_tests' == self.test_name: + test_list = self.test_report['test_results']['plaintext']['round_output'].keys() + if test_name not in test_list: + print('Error! Invalid test name. The report.show function requires a test_name input') + print('test_name has to be one of the following : ', end='') print(test_list) return - self._produce_graph(show_graph=True, fixed_input=fixed_input, fixed_output=fixed_output, + input_diff_values = [x['input_difference_value'] for x in self.test_report['test_results']['plaintext']['round_output'][test_name] if 'input_difference_value' in x.keys()] + if fixed_input_difference not in input_diff_values: + print('Error! Invalid input difference value. The report.show() function requires an input_difference_value input') + print('input_difference_value has to be one of the following :', end='') + print(input_diff_values) + return + elif 'neural_network_differential_distinguisher' in self.test_name: + input_diff_values = [x['input_difference_value'] for x in self.test_report['test_results']['plaintext']['round_output']['neural_network_differential_distinguisher']] + if fixed_input_difference not in input_diff_values: + print('Error! Invalid input difference value. The report.show() function requires an input_difference_value input') + print('The input difference value has to be one of the following :', end='') + print(input_diff_values) + return + self._produce_graph(show_graph=True, fixed_input=fixed_input, fixed_output=fixed_output, fixed_input_difference=fixed_input_difference, test_name=test_name) def _export(self, file_format, output_dir): @@ -202,16 +214,16 @@ def _export(self, file_format, output_dir): if 'statistical' in self.test_name: if file_format == '.csv': - df = pd.DataFrame.from_dict(self.test_report["randomness_test"]) + df = pd.DataFrame.from_dict(self.test_report['test_results'][0]["randomness_test"]) df.to_csv(output_dir + '/' + self.cipher.id + '/' + self.test_name + file_format) if file_format == '.json': with open(output_dir + '/' + self.cipher.id + '/' + self.test_name + file_format, 'w') as fp: - json.dump(self.test_report["randomness_test"], fp, default=lambda x: float(x)) + json.dump(self.test_report['test_results'][0]["randomness_test"], fp, default=lambda x: float(x)) if file_format == '.tex': with open(output_dir + '/' + self.cipher.id + '/' + self.test_name + file_format, 'w') as fp: - fp.write(pd.DataFrame(self.test_report["randomness_test"]).style.to_latex()) + fp.write(pd.DataFrame(self.test_report['test_results'][0]["randomness_test"]).style.to_latex()) elif 'component_analysis' in self.test_name: print('This method is not implemented yet for the component analysis test.') @@ -478,7 +490,7 @@ def _print_trail(self, word_size, state_size, key_state_size, verbose, show_word value = self.test_report['components_values'][comp_id]['value'] - bin_list = list(format(int(value, 16), 'b').zfill(4 * len(value)) if value[:2] != '0x' else 4 * len(value[2:])) if '*' not in value else list( + bin_list = list(format(int(value, 16), 'b').zfill(4 * len(value) if value[:2] != '0x' else 4 * len(value[2:]))) if '*' not in value else list( value[2:]) word_list = ['*' if '*' in ''.join(bin_list[x:x + word_size]) else word_denominator if ''.join(bin_list[x:x + word_size]).count('1') > 0 else '_' for x in @@ -572,13 +584,17 @@ def _produce_graph(self, output_directory=os.getcwd(), show_graph=False, fixed_i df_scores = pd.DataFrame( self.test_report['test_results']['plaintext']['cipher_output']['differences_scores'], index=['scores']).T + nr = self.test_report['test_results']['round_start'] df_result = pd.DataFrame( self.test_report['test_results']['plaintext']['cipher_output']['neural_distinguisher_test'][0][ - 'accuracies'], index=['accuracy_round' + str(i) for i in range(len( + 'accuracies'], index=['accuracy_round' + str(i) for i in range(nr, nr+len( self.test_report['test_results']['plaintext']['cipher_output']['neural_distinguisher_test'][0][ 'accuracies']))]) if show_graph: + print() + print() + print() print('RESULTS') print('plaintext_input_diff : ' + str( self.test_report['test_results']['plaintext']['cipher_output']['neural_distinguisher_test'][0][ @@ -600,17 +616,17 @@ def _produce_graph(self, output_directory=os.getcwd(), show_graph=False, fixed_i elif 'statistical' in self.test_name: if 'dieharder' in self.test_name: for dict in self.test_report['test_results']: - DieharderTests.generate_chart_round(dict, + DieharderTests._generate_chart_round(dict, output_directory + '/' + self.cipher.id + '/' + self.test_name, show_graph=True) - DieharderTests.generate_chart_all(self.test_report['test_results'], + DieharderTests._generate_chart_all(self.test_report['test_results'], output_directory + '/' + self.cipher.id + '/' + self.test_name, show_graph=True) elif 'nist' in self.test_name: for dict in self.test_report['test_results']: - StatisticalTests.generate_chart_round(dict, - output_directory + '/' + self.cipher.id + '/' + self.test_name, show_graph=True) - StatisticalTests.generate_chart_all(self.test_report['test_results'], - output_directory + '/' + self.cipher.id + '/' + self.test_name, show_graph=True) + NISTStatisticalTests._generate_chart_round(dict, + output_directory + '/' + self.cipher.id + '/' + self.test_name, show_graph=True) + NISTStatisticalTests._generate_chart_all(self.test_report['test_results'], + output_directory + '/' + self.cipher.id + '/' + self.test_name, show_graph=True) elif 'algebraic' in self.test_name: @@ -623,6 +639,7 @@ def _produce_graph(self, output_directory=os.getcwd(), show_graph=False, fixed_i z_text.append([str(x) for x in self.test_report['test_results'][test]]) fig = px.imshow(z, x=x, y=y, color_continuous_scale='Viridis', aspect="auto") fig.update_traces(text=z_text, texttemplate="%{text}") + fig.update(layout_coloraxis_showscale=False) fig.update_xaxes(side="top") if show_graph==False: fig.write_image(output_directory + '/test_results.png') @@ -723,7 +740,7 @@ def _produce_graph(self, output_directory=os.getcwd(), show_graph=False, fixed_i else: fig = px.line(df, range_x=[1, self.cipher.number_of_rounds], - range_y=[min(df[0]) - 1, max(df[0]) + 1]) + range_y=[0, 1]) fig.update_layout(xaxis_title="round", yaxis_title=res_key, showlegend=False) diff --git a/claasp/cipher_modules/statistical_tests/dieharder_statistical_tests.py b/claasp/cipher_modules/statistical_tests/dieharder_statistical_tests.py index f54333d6..9d3301da 100644 --- a/claasp/cipher_modules/statistical_tests/dieharder_statistical_tests.py +++ b/claasp/cipher_modules/statistical_tests/dieharder_statistical_tests.py @@ -97,6 +97,7 @@ def dieharder_statistical_tests(self, test_type, 'input_parameters': { 'test_name': 'dieharder_statistical_tests', + 'cipher': self.cipher, 'test_type': test_type, 'round_start': round_start, 'round_end': round_end, @@ -365,7 +366,7 @@ def _parse_report(report_filename): return report_dict @staticmethod - def generate_chart_round(report_dict, output_dir='', show_graph=False): + def _generate_chart_round(report_dict, output_dir='', show_graph=False): """ Generate the corresponding chart based on the parsed report dictionary. @@ -378,28 +379,6 @@ def generate_chart_round(report_dict, output_dir='', show_graph=False): - save the chart with filename f'dieharder_{report_dict["data_type"]}_{report_dict["cipher_name"]}_round_{report_dict["round"]}.png' - EXAMPLES:: - - sage: from claasp.cipher_modules.statistical_tests.dieharder_statistical_tests import DieharderTests - sage: result = DieharderTests._run_dieharder_statistical_tests_tool( # doctest: +SKIP - ....: f'claasp/cipher_modules/statistical_tests/input_data_example', # doctest: +SKIP - ....: ) # long time # doctest: +SKIP - ... - Dieharder Tests Finished!!! - - sage: from claasp.cipher_modules.statistical_tests.dieharder_statistical_tests import DieharderTests - sage: dict = DieharderTests.parse_report(f'dieharder_test_output.txt') # doctest: +SKIP - Parsing dieharder_test_output.txt is in progress. - Parsing dieharder_test_output.txt is finished. - - sage: dict['data_type'] = 'random' # doctest: +SKIP - sage: dict['data_type'] = 'random' # doctest: +SKIP - sage: dict['cipher_name'] = 'toy_cipher' # doctest: +SKIP - sage: dict['round'] = 1 # doctest: +SKIP - sage: dict['rounds'] = 1 # doctest: +SKIP - sage: DieharderTests.generate_chart_round(dict) # doctest: +SKIP - Drawing round 1 is in progress. - Drawing round 1 is finished. Please find the chart in file dieharder_random_toy_cipher_round_1.png. """ print(f'Drawing round {report_dict["round"]} is in progress.') x = [i for i in range(len(report_dict['randomness_test']))] @@ -432,7 +411,7 @@ def generate_chart_round(report_dict, output_dir='', show_graph=False): print(f'Drawing round {report_dict["round"]} is finished. Please find the chart in file {output_dir}.') @staticmethod - def generate_chart_all(report_dict_list, output_dir='', show_graph=False): + def _generate_chart_all(report_dict_list, output_dir='', show_graph=False): """ Generate the corresponding chart based on the parsed report dictionary. @@ -445,28 +424,6 @@ def generate_chart_all(report_dict_list, output_dir='', show_graph=False): - save the chart with filename f'dieharder_{report_dict["data_type"]}_{report_dict["cipher_name"]}_round_{report_dict["round"]}.png' - EXAMPLES:: - - sage: from claasp.cipher_modules.statistical_tests.dieharder_statistical_tests import DieharderTests - sage: result = DieharderTests.run_dieharder_statistical_tests_tool( # doctest: +SKIP - ....: f'claasp/cipher_modules/statistical_tests/input_data_example', # doctest: +SKIP - ....: ) # long time # doctest: +SKIP - ... - Dieharder Tests Finished!!! - - sage: from claasp.cipher_modules.statistical_tests.dieharder_statistical_tests import DieharderTests - sage: dict = DieharderTests.parse_report(f'dieharder_test_output.txt') # doctest: +SKIP - Parsing dieharder_test_output.txt is in progress. - Parsing dieharder_test_output.txt is finished. - - sage: dict['data_type'] = 'random' # doctest: +SKIP - sage: dict['cipher_name'] = 'toy_cipher' # doctest: +SKIP - sage: dict['round'] = 1 # doctest: +SKIP - sage: dict['rounds'] = 1 # doctest: +SKIP - sage: dict_list = [dict] # doctest: +SKIP - sage: DieharderTests.generate_chart_all(dict_list) # doctest: +SKIP - Drawing chart for all rounds is in progress. - Drawing chart for all rounds is in finished. Please find the chart in file dieharder_random_toy_cipher.png. """ print("Drawing chart for all rounds is in progress.") x = [i + 1 for i in range(report_dict_list[0]["rounds"])] @@ -515,7 +472,7 @@ def _write_execution_time(self, execution_description, execution_time): def _generate_dieharder_dicts(self, dataset, round_start, round_end, FLAG_CHART=False): dataset_folder = os.getcwd() + '/dataset' - dataset_filename = 'dieharder_input_' + self._cipher_primitive + dataset_filename = 'dieharder_input_' + self._cipher_primitive +'.txt' dataset_filename = os.path.join(dataset_folder, dataset_filename) dieharder_report_dicts = [] @@ -555,14 +512,14 @@ def _generate_dieharder_dicts(self, dataset, round_start, round_end, FLAG_CHART= dieharder_report_dicts.append(dieharder_report_dict) # generate round chart if FLAG_CHART: - self.generate_chart_round(dieharder_report_dict) + self._generate_chart_round(dieharder_report_dict) except OSError: print(f'Error in parsing report for round {round_number}.') # generate chart for all rounds if FLAG_CHART: try: - self.generate_chart_all(dieharder_report_dicts) + self._generate_chart_all(dieharder_report_dicts) except OSError: print(f'Error in generating all round chart.') diff --git a/claasp/cipher_modules/statistical_tests/nist_statistical_tests.py b/claasp/cipher_modules/statistical_tests/nist_statistical_tests.py index 63947e7e..453b7da8 100644 --- a/claasp/cipher_modules/statistical_tests/nist_statistical_tests.py +++ b/claasp/cipher_modules/statistical_tests/nist_statistical_tests.py @@ -49,7 +49,7 @@ } -class StatisticalTests: +class NISTStatisticalTests: def __init__(self, cipher): cipher.sort_cipher() @@ -99,6 +99,7 @@ def nist_statistical_tests(self, test_type, 'input_parameters': { 'test_name': 'nist_statistical_tests', + 'cipher': self.cipher, 'test_type': test_type, 'round_start': round_start, 'round_end': round_end, @@ -131,7 +132,8 @@ def nist_statistical_tests(self, test_type, self.number_of_samples = self.number_of_samples_in_one_sequence * (self.number_of_sequences + 1) self.bits_in_one_sequence = sample_size * self.number_of_samples_in_one_sequence - self._create_report_folder() + self._create_report_folder(statistical_test_option_list) + dataset = self.data_generator.generate_avalanche_dataset(input_index=self.input_index, number_of_samples=self.number_of_samples) @@ -149,8 +151,7 @@ def nist_statistical_tests(self, test_type, self.number_of_sequences = number_of_sequences self.number_of_samples = self.number_of_sequences + 1 self.bits_in_one_sequence = number_of_blocks_in_one_sample * self.cipher.output_bit_size - - self._create_report_folder() + self._create_report_folder(statistical_test_option_list) dataset = self.data_generator.generate_correlation_dataset(input_index=self.input_index, number_of_samples=self.number_of_samples, @@ -169,8 +170,7 @@ def nist_statistical_tests(self, test_type, self.number_of_sequences = number_of_sequences self.number_of_samples = self.number_of_sequences + 1 self.bits_in_one_sequence = number_of_blocks_in_one_sample * self.cipher.output_bit_size - - self._create_report_folder() + self._create_report_folder(statistical_test_option_list) dataset = self.data_generator.generate_cbc_dataset(input_index=self.input_index, number_of_samples=self.number_of_samples, @@ -188,8 +188,7 @@ def nist_statistical_tests(self, test_type, self.number_of_sequences = number_of_sequences self.number_of_samples = self.number_of_sequences + 1 self.bits_in_one_sequence = self.number_of_blocks_in_one_sample * self.cipher.output_bit_size - - self._create_report_folder() + self._create_report_folder(statistical_test_option_list) dataset = self.data_generator.generate_random_dataset(input_index=self.input_index, number_of_samples=self.number_of_samples, @@ -210,8 +209,7 @@ def nist_statistical_tests(self, test_type, ratio = min(1, (number_of_blocks_in_one_sample - 1 - n) / math.comb(n, 2)) self.number_of_blocks_in_one_sample = int(1 + n + math.ceil(math.comb(n, 2) * ratio)) self.bits_in_one_sequence = self.number_of_blocks_in_one_sample * self.cipher.output_bit_size - - self._create_report_folder() + self._create_report_folder(statistical_test_option_list) dataset = self.data_generator.generate_low_density_dataset(input_index=self.input_index, number_of_samples=self.number_of_samples, @@ -231,8 +229,7 @@ def nist_statistical_tests(self, test_type, ratio = min(1, (number_of_blocks_in_one_sample - 1 - n) / math.comb(n, 2)) self.number_of_blocks_in_one_sample = int(1 + n + math.ceil(math.comb(n, 2) * ratio)) self.bits_in_one_sequence = self.number_of_blocks_in_one_sample * self.cipher.output_bit_size - - self._create_report_folder() + self._create_report_folder(statistical_test_option_list) dataset = self.data_generator.generate_high_density_dataset(input_index=self.input_index, number_of_samples=self.number_of_samples, @@ -450,7 +447,7 @@ def _parse_report(report_filename, statistical_test_option_list='1' + 14 * '0'): return report_dict @staticmethod - def generate_chart_round(report_dict, output_dir='', show_graph=False): + def _generate_chart_round(report_dict, output_dir='', show_graph=False): """ Generate the corresponding chart based on the parsed report dictionary. @@ -463,20 +460,6 @@ def generate_chart_round(report_dict, output_dir='', show_graph=False): - save the chart with filename f'nist_{report_dict["data_type"]}_{report_dict["cipher_name"]}_round_{report_dict["round"]}.png' - EXAMPLES:: - - sage: from claasp.cipher_modules.statistical_tests.nist_statistical_tests import StatisticalTests - sage: dict = StatisticalTests.parse_report(f'claasp/cipher_modules/statistical_tests/finalAnalysisReportExample.txt') - Parsing claasp/cipher_modules/statistical_tests/finalAnalysisReportExample.txt is in progress. - Parsing claasp/cipher_modules/statistical_tests/finalAnalysisReportExample.txt is finished. - - sage: dict['data_type'] = 'random' - sage: dict['cipher_name'] = 'toy_cipher' - sage: dict['round'] = 1 - sage: dict['rounds'] = 1 - sage: StatisticalTests.generate_chart_round(dict) - Drawing round 1 is in progress. - Drawing round 1 is finished. """ print(f'Drawing round {report_dict["round"]} is in progress.') x = [test['test_id'] for test in report_dict['randomness_test']] @@ -514,7 +497,7 @@ def generate_chart_round(report_dict, output_dir='', show_graph=False): print(f'Drawing round {report_dict["round"]} is finished.') @staticmethod - def generate_chart_all(report_dict_list, report_folder="", show_graph=False): + def _generate_chart_all(report_dict_list, report_folder="", show_graph=False): """ Generate the corresponding chart based on the list of parsed report dictionary for all rounds. @@ -526,29 +509,11 @@ def generate_chart_all(report_dict_list, report_folder="", show_graph=False): - save the chart with filename f'nist_{data_type}_{cipher_name}.png' - EXAMPLES:: - - sage: from claasp.cipher_modules.statistical_tests.nist_statistical_tests import StatisticalTests - sage: dict = StatisticalTests.parse_report(f'claasp/cipher_modules/statistical_tests/finalAnalysisReportExample.txt') - Parsing claasp/cipher_modules/statistical_tests/finalAnalysisReportExample.txt is in progress. - Parsing claasp/cipher_modules/statistical_tests/finalAnalysisReportExample.txt is finished. - - sage: dict['data_type'] = 'random' - sage: dict['cipher_name'] = 'toy_cipher' - sage: dict['round'] = 1 - sage: dict['rounds'] = 1 - sage: dict_list = [dict] - sage: StatisticalTests.generate_chart_all(dict_list) - Drawing chart for all rounds is in progress. - Drawing chart for all rounds is in finished. """ print("Drawing chart for all rounds is in progress.") x = [i + 1 for i in range(report_dict_list[0]["rounds"])] y = [0 for _ in range(report_dict_list[0]["rounds"])] for i in range(len(report_dict_list)): - print(report_dict_list[i]["round"]) - print(len(y)) - print() y[report_dict_list[i]["round"]-1] = report_dict_list[i]["passed_tests"] random_round = -1 @@ -582,9 +547,9 @@ def generate_chart_all(report_dict_list, report_folder="", show_graph=False): plt.close() print(f'Drawing chart for all rounds is in finished.') - def _create_report_folder(self): + def _create_report_folder(self,statistical_test_option_list): self.report_folder = os.path.join(self.folder_prefix, - f'{self._cipher_primitive}_{self.dataset_type.name}_index{self.input_index}_{self.number_of_sequences}lines_{self.bits_in_one_sequence}bits') + f'{self._cipher_primitive}_{self.dataset_type.name}_index{self.input_index}_{self.number_of_sequences}lines_{self.bits_in_one_sequence}bits_{statistical_test_option_list}test_option_list') try: os.makedirs(self.report_folder) except OSError: @@ -632,12 +597,10 @@ def _generate_nist_dicts(self, dataset, round_start, round_end, statistical_test sts_execution_time = time.time() - sts_execution_time try: shutil.move(nist_local_experiment_folder, report_folder_round) - except OSError as e: - print(f'Error: {e.strerror}') - print( - f'Please remove the existed folder {report_folder_round} ' - f'or indicate another folder for saving the NIST STS reports.') - continue + except OSError: + shutil.rmtree(report_folder_round) + shutil.move(nist_local_experiment_folder, report_folder_round) + self._write_execution_time(f'Compute round {round_number}', sts_execution_time) try: @@ -655,9 +618,9 @@ def _generate_nist_dicts(self, dataset, round_start, round_end, statistical_test print("Finished.") return sts_report_dicts - def generate_chart_for_all_rounds(self, flag_chart, sts_report_dicts): + def _generate_chart_for_all_rounds(self, flag_chart, sts_report_dicts): if flag_chart: try: - self.generate_chart_all(sts_report_dicts, self.report_folder) + self._generate_chart_all(sts_report_dicts, self.report_folder) except OSError: print("Error in generating all round chart.") diff --git a/claasp/utils/utils.py b/claasp/utils/utils.py index 86191020..005a9517 100644 --- a/claasp/utils/utils.py +++ b/claasp/utils/utils.py @@ -369,6 +369,9 @@ def pprint_dictionary_to_file(dictionary, name_file): sage: import os sage: os.remove(f"{tii_dir_path}/test_json") """ + + if 'cipher' in dictionary.keys(): + dictionary['cipher'] = dictionary['cipher'].id dictionary_json = json.loads(str(dictionary).replace("'", '"')) source_file = open(name_file, 'w') print(json.dumps(dictionary_json, indent=4), file=source_file) diff --git a/tests/benchmark/statistical_tests_test.py b/tests/benchmark/statistical_tests_test.py index 1a88805b..7da064e9 100644 --- a/tests/benchmark/statistical_tests_test.py +++ b/tests/benchmark/statistical_tests_test.py @@ -2,17 +2,17 @@ from claasp.ciphers.block_ciphers.aes_block_cipher import AESBlockCipher from claasp.ciphers.block_ciphers.speck_block_cipher import SpeckBlockCipher -from claasp.cipher_modules.statistical_tests.nist_statistical_tests import StatisticalTests +from claasp.cipher_modules.statistical_tests.nist_statistical_tests import NISTStatisticalTests speck = SpeckBlockCipher() aes = AESBlockCipher() def test_run_avalanche_nist_statistics_test_with_speck_cipher(benchmark): - tests = StatisticalTests(speck) + tests = NISTStatisticalTests(speck) benchmark(tests.run_avalanche_nist_statistics_test, 0, 10, 10) def test_run_avalanche_nist_statistics_test_with_aes_cipher(benchmark): - tests = StatisticalTests(aes) + tests = NISTStatisticalTests(aes) benchmark(tests.run_avalanche_nist_statistics_test, 0, 10, 10) diff --git a/tests/unit/cipher_modules/continuous_diffusion_analysis_test.py b/tests/unit/cipher_modules/continuous_diffusion_analysis_test.py index c226768e..b7d69b9a 100644 --- a/tests/unit/cipher_modules/continuous_diffusion_analysis_test.py +++ b/tests/unit/cipher_modules/continuous_diffusion_analysis_test.py @@ -16,7 +16,7 @@ def test_continuous_tests_report(): speck = SpeckBlockCipher(number_of_rounds=2) cda = ContinuousDiffusionAnalysis(speck) cda_for_repo = cda.continuous_diffusion_tests() - cda_repo = Report(speck, cda_for_repo) + cda_repo = Report(cda_for_repo) cda_repo.save_as_image() diff --git a/tests/unit/cipher_modules/models/cp/cp_models/cp_deterministic_truncated_xor_differential_model_test.py b/tests/unit/cipher_modules/models/cp/cp_models/cp_deterministic_truncated_xor_differential_model_test.py index a376ade8..ccd604aa 100644 --- a/tests/unit/cipher_modules/models/cp/cp_models/cp_deterministic_truncated_xor_differential_model_test.py +++ b/tests/unit/cipher_modules/models/cp/cp_models/cp_deterministic_truncated_xor_differential_model_test.py @@ -40,7 +40,7 @@ def test_find_all_deterministic_truncated_xor_differential_trail(): assert len(trail) == 4 for i in range(len(trail)): - assert trail[i]['cipher_id'] == 'speck_p32_k64_o32_r3' + assert str(trail[i]['cipher']) == 'speck_p32_k64_o32_r3' assert trail[i]['model_type'] == 'deterministic_truncated_xor_differential' assert trail[i]['model_type'] == 'deterministic_truncated_xor_differential' assert trail[i]['solver_name'] == 'Chuffed' @@ -54,7 +54,7 @@ def test_find_one_deterministic_truncated_xor_differential_trail(): key = set_fixed_variables(component_id='key', constraint_type='equal', bit_positions=range(64), bit_values=[0] * 64) trail = cp.find_one_deterministic_truncated_xor_differential_trail(1, [plaintext, key], 'Chuffed') - assert trail[0]['cipher_id'] == 'speck_p32_k64_o32_r1' + assert str(trail[0]['cipher']) == 'speck_p32_k64_o32_r1' assert trail[0]['components_values']['key']['value'] == '000000000000000000000000000000000000000000000000000000' \ '0000000000' diff --git a/tests/unit/cipher_modules/models/cp/cp_models/cp_impossible_xor_differential_model_test.py b/tests/unit/cipher_modules/models/cp/cp_models/cp_impossible_xor_differential_model_test.py index ef37121e..69efd9bd 100644 --- a/tests/unit/cipher_modules/models/cp/cp_models/cp_impossible_xor_differential_model_test.py +++ b/tests/unit/cipher_modules/models/cp/cp_models/cp_impossible_xor_differential_model_test.py @@ -41,7 +41,7 @@ def find_one_impossible_xor_differential_trail(): bit_positions=range(64), bit_values=[0] * 64) trail = cp.find_one_impossible_xor_differential_trail(6, [plaintext, ciphertext, key], 'Chuffed', 3) - assert trail['cipher_id'] == 'speck_p32_k64_o32_r6' + assert str(trail['cipher']) == 'speck_p32_k64_o32_r6' assert trail['model_type'] == 'impossible_xor_differential_one_solution' assert trail['solver_name'] == 'Chuffed' diff --git a/tests/unit/cipher_modules/models/cp/cp_models/cp_xor_differential_trail_search_fixing_number_of_active_sboxes_model_test.py b/tests/unit/cipher_modules/models/cp/cp_models/cp_xor_differential_trail_search_fixing_number_of_active_sboxes_model_test.py index 3d8028cf..c51bc28e 100644 --- a/tests/unit/cipher_modules/models/cp/cp_models/cp_xor_differential_trail_search_fixing_number_of_active_sboxes_model_test.py +++ b/tests/unit/cipher_modules/models/cp/cp_models/cp_xor_differential_trail_search_fixing_number_of_active_sboxes_model_test.py @@ -24,7 +24,7 @@ def test_find_lowest_weight_xor_differential_trail(): set_fixed_variables('plaintext', 'not_equal', range(128), integer_to_bit_list(0, 128, 'little'))] solution = cp.find_lowest_weight_xor_differential_trail(fixed_variables, 'Chuffed', 'Chuffed') - assert solution['cipher_id'] == 'aes_block_cipher_k128_p128_o128_r2' + assert str(solution['cipher']) == 'aes_block_cipher_k128_p128_o128_r2' assert solution['model_type'] == 'xor_differential' assert solution['solver_name'] == 'Chuffed' assert solution['total_weight'] == '30.0' @@ -42,7 +42,7 @@ def test_find_one_xor_differential_trail(): set_fixed_variables('plaintext', 'not_equal', range(128), integer_to_bit_list(0, 128, 'little'))] solution = cp.find_one_xor_differential_trail(fixed_variables, 'Chuffed', 'Chuffed') - assert solution['cipher_id'] == 'aes_block_cipher_k128_p128_o128_r2' + assert str(solution['cipher']) == 'aes_block_cipher_k128_p128_o128_r2' assert solution['model_type'] == 'xor_differential' assert solution['solver_name'] == 'Chuffed' assert eval(solution['total_weight']) >= 0.0 @@ -57,7 +57,7 @@ def test_find_one_xor_differential_trail_with_fixed_weight(): set_fixed_variables('plaintext', 'not_equal', range(128), integer_to_bit_list(0, 128, 'little'))] solution = cp.find_one_xor_differential_trail_with_fixed_weight(224, fixed_variables, 'Chuffed', 'Chuffed') - assert solution['cipher_id'] == 'aes_block_cipher_k128_p128_o128_r2' + assert str(solution['cipher']) == 'aes_block_cipher_k128_p128_o128_r2' assert solution['model_type'] == 'xor_differential' assert solution['solver_name'] == 'Chuffed' assert eval(solution['total_weight']) == 224.0 @@ -74,7 +74,7 @@ def test_solve_full_two_steps_xor_differential_model(): set_fixed_variables('key', 'not_equal', list(range(128)), integer_to_bit_list(0, 128, 'little'))] constraints = cp.solve_full_two_steps_xor_differential_model('xor_differential_one_solution', -1, fixed_variables, 'Chuffed', 'Chuffed') - assert constraints['cipher_id'] == 'aes_block_cipher_k128_p128_o128_r2' + assert str(constraints['cipher']) == 'aes_block_cipher_k128_p128_o128_r2' assert eval('0x' + constraints['components_values']['intermediate_output_0_35']['value']) >= 0 assert constraints['components_values']['intermediate_output_0_35']['weight'] == 0 assert eval('0x' + constraints['components_values']['xor_0_36']['value']) >= 0 diff --git a/tests/unit/cipher_modules/models/cp/cp_models/cp_xor_differential_trail_search_model_test.py b/tests/unit/cipher_modules/models/cp/cp_models/cp_xor_differential_trail_search_model_test.py index 3a135b7c..6fa4ed3c 100644 --- a/tests/unit/cipher_modules/models/cp/cp_models/cp_xor_differential_trail_search_model_test.py +++ b/tests/unit/cipher_modules/models/cp/cp_models/cp_xor_differential_trail_search_model_test.py @@ -44,7 +44,7 @@ def test_find_lowest_weight_xor_differential_trail(): set_fixed_variables('plaintext', 'not_equal', list(range(32)), integer_to_bit_list(0, 32, 'big'))] trail = cp.find_lowest_weight_xor_differential_trail(fixed_values, 'Chuffed') - assert trail['cipher_id'] == 'speck_p32_k64_o32_r5' + assert str(trail['cipher']) == 'speck_p32_k64_o32_r5' assert trail['total_weight'] == '9.0' assert eval('0x' + trail['components_values']['cipher_output_4_12']['value']) >= 0 assert trail['components_values']['cipher_output_4_12']['weight'] == 0 @@ -57,7 +57,7 @@ def test_find_one_xor_differential_trail(): bit_positions=range(32), bit_values=[0] * 32) trail = cp.find_one_xor_differential_trail([plaintext], 'Chuffed') - assert trail['cipher_id'] == 'speck_p32_k64_o32_r2' + assert str(trail['cipher']) == 'speck_p32_k64_o32_r2' assert trail['model_type'] == 'xor_differential_one_solution' assert eval('0x' + trail['components_values']['cipher_output_1_12']['value']) >= 0 assert trail['components_values']['cipher_output_1_12']['weight'] == 0 @@ -71,7 +71,7 @@ def test_find_one_xor_differential_trail_with_fixed_weight(): bit_positions=range(32), bit_values=[0] * 32) trail = cp.find_one_xor_differential_trail_with_fixed_weight(9, [plaintext], 'Chuffed') - assert trail['cipher_id'] == 'speck_p32_k64_o32_r5' + assert str(trail['cipher']) == 'speck_p32_k64_o32_r5' assert trail['model_type'] == 'xor_differential_one_solution' assert eval('0x' + trail['components_values']['intermediate_output_0_5']['value']) >= 0 assert trail['components_values']['intermediate_output_0_5']['weight'] == 0 diff --git a/tests/unit/cipher_modules/models/cp/cp_models/cp_xor_linear_model_test.py b/tests/unit/cipher_modules/models/cp/cp_models/cp_xor_linear_model_test.py index 4206afe5..2727204f 100644 --- a/tests/unit/cipher_modules/models/cp/cp_models/cp_xor_linear_model_test.py +++ b/tests/unit/cipher_modules/models/cp/cp_models/cp_xor_linear_model_test.py @@ -54,7 +54,7 @@ def test_find_lowest_weight_xor_linear_trail(): set_fixed_variables('plaintext', 'not_equal', list(range(32)), integer_to_bit_list(0, 32, 'little'))] trail = cp.find_lowest_weight_xor_linear_trail(fixed_variables) - assert trail['cipher_id'] == 'speck_p32_k64_o32_r4' + assert str(trail['cipher']) == 'speck_p32_k64_o32_r4' assert eval('0x' + trail['components_values']['cipher_output_3_12_o']['value']) >= 0 assert trail['components_values']['cipher_output_3_12_o']['weight'] == 0 assert trail['total_weight'] == '3.0' @@ -68,7 +68,7 @@ def test_find_one_xor_linear_trail(): set_fixed_variables('plaintext', 'not_equal', list(range(32)), integer_to_bit_list(0, 32, 'little'))] trail = cp.find_one_xor_linear_trail(fixed_variables) - assert trail['cipher_id'] == 'speck_p32_k64_o32_r4' + assert str(trail['cipher']) == 'speck_p32_k64_o32_r4' assert trail['components_values']['plaintext']['weight'] == 0 assert eval('0x' + trail['components_values']['plaintext']['value']) > 0 assert trail['components_values']['cipher_output_3_12_o']['weight'] == 0 @@ -83,7 +83,7 @@ def test_find_one_xor_linear_trail_with_fixed_weight(): fixed_variables = [ set_fixed_variables('plaintext', 'not_equal', list(range(32)), integer_to_bit_list(0, 32, 'little'))] trail = cp.find_one_xor_linear_trail_with_fixed_weight(3, fixed_variables) - assert trail['cipher_id'] == 'speck_p32_k64_o32_r4' + assert str(trail['cipher']) == 'speck_p32_k64_o32_r4' assert trail['model_type'] == 'xor_linear_one_solution' assert trail['total_weight'] == '3.0' diff --git a/tests/unit/cipher_modules/models/milp/milp_model_test.py b/tests/unit/cipher_modules/models/milp/milp_model_test.py index 802a1672..e4548e21 100644 --- a/tests/unit/cipher_modules/models/milp/milp_model_test.py +++ b/tests/unit/cipher_modules/models/milp/milp_model_test.py @@ -87,7 +87,7 @@ def test_solve(): milp.add_constraints_to_build_in_sage_milp_class() differential_solution = milp.solve("xor_differential") - assert differential_solution['cipher_id'] == 'speck_p32_k64_o32_r4' + assert str(differential_solution['cipher']) == 'speck_p32_k64_o32_r4' assert differential_solution['model_type'] == 'xor_differential' assert differential_solution['components_values']['key']['weight'] == 0 assert differential_solution['components_values']['modadd_0_1']['weight'] >= 0 @@ -99,7 +99,7 @@ def test_solve(): milp.add_constraints_to_build_in_sage_milp_class() linear_solution = milp.solve("xor_linear") - assert linear_solution['cipher_id'] == 'speck_p32_k64_o32_r4' + assert str(linear_solution['cipher']) == 'speck_p32_k64_o32_r4' assert linear_solution['model_type'] == 'xor_linear' assert differential_solution['components_values']['key']['weight'] == 0 assert linear_solution['components_values']['modadd_1_7_i']['weight'] >= 0 diff --git a/tests/unit/cipher_modules/models/milp/milp_models/milp_xor_differential_model_test.py b/tests/unit/cipher_modules/models/milp/milp_models/milp_xor_differential_model_test.py index 7f15e831..a57cdaa4 100644 --- a/tests/unit/cipher_modules/models/milp/milp_models/milp_xor_differential_model_test.py +++ b/tests/unit/cipher_modules/models/milp/milp_models/milp_xor_differential_model_test.py @@ -13,7 +13,7 @@ def test_find_all_xor_differential_trails_with_fixed_weight(): assert len(trail) == 6 for i in range(len(trail)): - assert trail[i]['cipher_id'] == 'speck_p8_k16_o8_r2' + assert str(trail[i]['cipher']) == 'speck_p8_k16_o8_r2' assert trail[i]['total_weight'] == 1.0 assert eval(trail[i]['components_values']['plaintext']['value']) > 0 assert eval(trail[i]['components_values']['key']['value']) == 0 diff --git a/tests/unit/cipher_modules/models/milp/milp_models/milp_xor_linear_model_test.py b/tests/unit/cipher_modules/models/milp/milp_models/milp_xor_linear_model_test.py index 3e280932..9260df2c 100644 --- a/tests/unit/cipher_modules/models/milp/milp_models/milp_xor_linear_model_test.py +++ b/tests/unit/cipher_modules/models/milp/milp_models/milp_xor_linear_model_test.py @@ -26,7 +26,7 @@ def test_find_all_xor_linear_trails_with_fixed_weight(): assert len(trails) == 12 for i in range(len(trails)): - assert trails[i]['cipher_id'] == 'speck_p8_k16_o8_r3' + assert str(trails[i]['cipher']) == 'speck_p8_k16_o8_r3' assert trails[i]['total_weight'] == 1.0 assert eval(trails[i]['components_values']['plaintext']['value']) > 0 assert eval(trails[i]['components_values']['key_0_2']['value']) >= 0 @@ -46,7 +46,7 @@ def test_find_all_xor_linear_trails_with_weight_at_most(): assert len(trails) == 13 for i in range(len(trails)): - assert trails[i]['cipher_id'] == 'speck_p8_k16_o8_r3' + assert str(trails[i]['cipher']) == 'speck_p8_k16_o8_r3' assert trails[i]['total_weight'] <= 1.0 assert trails[i]['total_weight'] >= 0.0 assert eval(trails[i]['components_values']['plaintext']['value']) > 0 diff --git a/tests/unit/cipher_modules/models/models_utils_test.py b/tests/unit/cipher_modules/models/models_utils_test.py index eaf88158..0a7330e7 100644 --- a/tests/unit/cipher_modules/models/models_utils_test.py +++ b/tests/unit/cipher_modules/models/models_utils_test.py @@ -55,7 +55,7 @@ def test_to_bias_for_xor_linear_trail(): trail = milp.find_lowest_weight_xor_linear_trail([plaintext]) solution = to_bias_for_xor_linear_trail(speck, trail) - assert solution['cipher_id'] == 'speck_p32_k64_o32_r4' + assert str(solution['cipher']) == 'speck_p32_k64_o32_r4' assert solution['total_weight'] == 4.0 assert solution['measure'] == 'bias' @@ -68,7 +68,7 @@ def test_to_probability_for_xor_linear_trail(): trail = milp.find_lowest_weight_xor_linear_trail([plaintext]) solution = to_probability_for_xor_linear_trail(speck, trail) - assert solution['cipher_id'] == 'speck_p32_k64_o32_r4' + assert str(solution['cipher']) == 'speck_p32_k64_o32_r4' assert solution['measure'] == 'probability' assert solution['total_weight'] == 0.83 @@ -81,7 +81,7 @@ def test_to_correlation_for_xor_linear_trail(): trail = milp.find_lowest_weight_xor_linear_trail([plaintext]) solution = to_correlation_for_xor_linear_trail(speck, trail) - assert solution['cipher_id'] == 'speck_p32_k64_o32_r4' + assert str(solution['cipher']) == 'speck_p32_k64_o32_r4' assert solution['measure'] == 'correlation' assert solution['total_weight'] == 3.0 diff --git a/tests/unit/cipher_modules/models/sat/sat_model_test.py b/tests/unit/cipher_modules/models/sat/sat_model_test.py index 40c4b06f..221761ed 100644 --- a/tests/unit/cipher_modules/models/sat/sat_model_test.py +++ b/tests/unit/cipher_modules/models/sat/sat_model_test.py @@ -14,7 +14,7 @@ def test_solve(): sat = SatCipherModel(tea) sat.build_cipher_model() solution = sat.solve('cipher', solver_name='cryptominisat') - assert solution['cipher_id'] == 'tea_p64_k128_o64_r32' + assert str(solution['cipher']) == 'tea_p64_k128_o64_r32' assert solution['solver_name'] == 'cryptominisat' assert eval('0x' + solution['components_values']['modadd_0_3']['value']) >= 0 assert eval('0x' + solution['components_values']['cipher_output_31_16']['value']) >= 0 @@ -23,7 +23,7 @@ def test_solve(): sat = SatCipherModel(simon) sat.build_cipher_model() solution = sat.solve('cipher', solver_name='cryptominisat_sage') - assert solution['cipher_id'] == 'simon_p32_k64_o32_r32' + assert str(solution['cipher']) == 'simon_p32_k64_o32_r32' assert solution['solver_name'] == 'cryptominisat' assert eval('0x' + solution['components_values']['rot_0_3']['value']) >= 0 assert eval('0x' + solution['components_values']['cipher_output_31_13']['value']) >= 0 diff --git a/tests/unit/cipher_modules/models/sat/sat_models/sat_cipher_model_test.py b/tests/unit/cipher_modules/models/sat/sat_models/sat_cipher_model_test.py index 8af3bbd3..48808515 100644 --- a/tests/unit/cipher_modules/models/sat/sat_models/sat_cipher_model_test.py +++ b/tests/unit/cipher_modules/models/sat/sat_models/sat_cipher_model_test.py @@ -14,7 +14,7 @@ def test_find_missing_bits(): missing_bits = sat.find_missing_bits(fixed_values=[ciphertext]) - assert missing_bits['cipher_id'] == 'speck_p32_k64_o32_r22' + assert str(missing_bits['cipher']) == 'speck_p32_k64_o32_r22' assert missing_bits['model_type'] == 'cipher' assert missing_bits['solver_name'] == 'cryptominisat' assert missing_bits['components_values'][cipher_output_id] == {'value': '1234abcd'} diff --git a/tests/unit/cipher_modules/models/sat/sat_models/sat_xor_differential_model_test.py b/tests/unit/cipher_modules/models/sat/sat_models/sat_xor_differential_model_test.py index 323c63ce..53cb1365 100644 --- a/tests/unit/cipher_modules/models/sat/sat_models/sat_xor_differential_model_test.py +++ b/tests/unit/cipher_modules/models/sat/sat_models/sat_xor_differential_model_test.py @@ -4,6 +4,7 @@ from claasp.cipher_modules.models.utils import set_fixed_variables, integer_to_bit_list from claasp.cipher_modules.models.sat.sat_models.sat_xor_differential_model import SatXorDifferentialModel +speck_5rounds = SpeckBlockCipher(number_of_rounds=5) def test_find_all_xor_differential_trails_with_fixed_weight(): speck = SpeckBlockCipher(number_of_rounds=5) sat = SatXorDifferentialModel(speck, window_size_weight_pr_vars=1) @@ -17,7 +18,7 @@ def test_find_all_xor_differential_trails_with_fixed_weight(): def test_find_all_xor_differential_trails_with_weight_at_most(): - speck = SpeckBlockCipher(number_of_rounds=5) + speck = speck_5rounds sat = SatXorDifferentialModel(speck) plaintext = set_fixed_variables(component_id='plaintext', constraint_type='not_equal', bit_positions=range(32), bit_values=integer_to_bit_list(0, 32, 'big')) @@ -29,7 +30,7 @@ def test_find_all_xor_differential_trails_with_weight_at_most(): def test_find_lowest_weight_xor_differential_trail(): - speck = SpeckBlockCipher(number_of_rounds=5) + speck = speck_5rounds sat = SatXorDifferentialModel(speck) plaintext = set_fixed_variables(component_id='plaintext', constraint_type='not_equal', bit_positions=range(32), bit_values=(0,) * 32) @@ -41,13 +42,13 @@ def test_find_lowest_weight_xor_differential_trail(): def test_find_one_xor_differential_trail(): - speck = SpeckBlockCipher(number_of_rounds=5) + speck = speck_5rounds sat = SatXorDifferentialModel(speck) plaintext = set_fixed_variables(component_id='plaintext', constraint_type='not_equal', bit_positions=range(32), bit_values=integer_to_bit_list(0, 32, 'big')) trail = sat.find_one_xor_differential_trail(fixed_values=[plaintext]) - assert trail['cipher_id'] == 'speck_p32_k64_o32_r5' + assert str(trail['cipher']) == 'speck_p32_k64_o32_r5' assert trail['model_type'] == 'xor_differential' assert trail['solver_name'] == 'cryptominisat' assert trail['status'] == 'SATISFIABLE' @@ -103,53 +104,46 @@ def test_build_xor_differential_trail_model_fixed_weight_and_parkissat(): assert int(result['total_weight']) == int(3.0) -def test_differential_in_related_key_scenario_speck3264(): - def repeat_input_difference(input_difference_, number_of_samples_, number_of_bytes_): - bytes_array = input_difference_.to_bytes(number_of_bytes_, 'big') - np_array = np.array(list(bytes_array), dtype=np.uint8) - column_array = np_array.reshape(-1, 1) - return np.tile(column_array, (1, number_of_samples_)) +def repeat_input_difference(input_difference_, number_of_samples_, number_of_bytes_): + bytes_array = input_difference_.to_bytes(number_of_bytes_, 'big') + np_array = np.array(list(bytes_array), dtype=np.uint8) + column_array = np_array.reshape(-1, 1) + return np.tile(column_array, (1, number_of_samples_)) +def test_differential_in_related_key_scenario_speck3264(): rng = np.random.default_rng(seed=42) - number_of_samples = 2**22 - input_difference = 0x2a14001 - output_difference = 0x850a810a - key_difference = 0x2800020000800001 + number_of_samples = 2**23 + input_difference = 0x00402000 + output_difference = 0x0 + key_difference = 0x000afa3d0030a000 input_difference_data = repeat_input_difference(input_difference, number_of_samples, 4) output_difference_data = repeat_input_difference(output_difference, number_of_samples, 4) key_difference_data = repeat_input_difference(key_difference, number_of_samples, 8) - speck = SpeckBlockCipher(block_bit_size=32, key_bit_size=64, number_of_rounds=7) key_data = rng.integers(low=0, high=256, size=(8, number_of_samples), dtype=np.uint8) - plaintext_data1 = rng.integers(low=0, high=256, size=(4, number_of_samples), dtype=np.uint8) plaintext_data2 = plaintext_data1 ^ input_difference_data - ciphertext1 = speck.evaluate_vectorized([plaintext_data1, key_data]) - ciphertext2 = speck.evaluate_vectorized([plaintext_data2, key_data ^ key_difference_data]) - total = np.sum(ciphertext1[0] ^ ciphertext2[0] == output_difference_data.T) + ciphertext1 = speck_5rounds.evaluate_vectorized([plaintext_data1, key_data]) + ciphertext2 = speck_5rounds.evaluate_vectorized([plaintext_data2, key_data ^ key_difference_data]) + rows_all_true = np.all((ciphertext1[0] ^ ciphertext2[0] == output_difference_data.T), axis=1) + total = np.count_nonzero(rows_all_true) import math - total_prob_weight = math.log(total, 2) - assert 18 > total_prob_weight > 12 + total_prob_weight = math.log(total/number_of_samples, 2) + assert 21 > abs(total_prob_weight) > 12 def test_differential_in_single_key_scenario_speck3264(): - def repeat_input_difference(input_difference_, number_of_samples_, number_of_bytes_): - bytes_array = input_difference_.to_bytes(number_of_bytes_, 'big') - np_array = np.array(list(bytes_array), dtype=np.uint8) - column_array = np_array.reshape(-1, 1) - return np.tile(column_array, (1, number_of_samples_)) - rng = np.random.default_rng(seed=42) - number_of_samples = 2**22 + number_of_samples = 2**23 input_difference = 0x20400040 output_difference = 0x106040E0 input_difference_data = repeat_input_difference(input_difference, number_of_samples, 4) output_difference_data = repeat_input_difference(output_difference, number_of_samples, 4) - speck = SpeckBlockCipher(block_bit_size=32, key_bit_size=64, number_of_rounds=5) key_data = rng.integers(low=0, high=256, size=(8, number_of_samples), dtype=np.uint8) plaintext_data1 = rng.integers(low=0, high=256, size=(4, number_of_samples), dtype=np.uint8) plaintext_data2 = plaintext_data1 ^ input_difference_data - ciphertext1 = speck.evaluate_vectorized([plaintext_data1, key_data]) - ciphertext2 = speck.evaluate_vectorized([plaintext_data2, key_data]) - total = np.sum(ciphertext1[0] ^ ciphertext2[0] == output_difference_data.T) + ciphertext1 = speck_5rounds.evaluate_vectorized([plaintext_data1, key_data]) + ciphertext2 = speck_5rounds.evaluate_vectorized([plaintext_data2, key_data]) + rows_all_true = np.all((ciphertext1[0] ^ ciphertext2[0] == output_difference_data.T), axis=1) + total = np.count_nonzero(rows_all_true) import math - total_prob_weight = math.log(total, 2) - assert 21 > total_prob_weight > 13 \ No newline at end of file + total_prob_weight = math.log(total/number_of_samples, 2) + assert 21 > abs(total_prob_weight) > 13 \ No newline at end of file diff --git a/tests/unit/cipher_modules/models/sat/sat_models/sat_xor_linear_model_test.py b/tests/unit/cipher_modules/models/sat/sat_models/sat_xor_linear_model_test.py index 6501182d..d045e6f3 100644 --- a/tests/unit/cipher_modules/models/sat/sat_models/sat_xor_linear_model_test.py +++ b/tests/unit/cipher_modules/models/sat/sat_models/sat_xor_linear_model_test.py @@ -43,7 +43,7 @@ def test_find_one_xor_linear_trail(): bit_positions=range(32), bit_values=integer_to_bit_list(0, 32, 'big')) trail = sat.find_one_xor_linear_trail(fixed_values=[plaintext]) - assert trail['cipher_id'] == 'speck_p32_k64_o32_r4' + assert str(trail['cipher']) == 'speck_p32_k64_o32_r4' assert trail['model_type'] == 'xor_linear' assert trail['solver_name'] == 'cryptominisat' assert trail['status'] == 'SATISFIABLE' diff --git a/tests/unit/cipher_modules/models/smt/smt_models/smt_cipher_model_test.py b/tests/unit/cipher_modules/models/smt/smt_models/smt_cipher_model_test.py index 193abf64..2514a004 100644 --- a/tests/unit/cipher_modules/models/smt/smt_models/smt_cipher_model_test.py +++ b/tests/unit/cipher_modules/models/smt/smt_models/smt_cipher_model_test.py @@ -14,7 +14,7 @@ def test_find_missing_bits(): missing_bits = smt.find_missing_bits(fixed_values=[ciphertext]) - assert missing_bits['cipher_id'] == 'speck_p32_k64_o32_r22' + assert str(missing_bits['cipher']) == 'speck_p32_k64_o32_r22' assert missing_bits['model_type'] == 'cipher' assert missing_bits['solver_name'] == 'z3' assert missing_bits['components_values'][cipher_output_id] == {'value': '1234abcd'} diff --git a/tests/unit/cipher_modules/models/smt/smt_models/smt_xor_differential_model_test.py b/tests/unit/cipher_modules/models/smt/smt_models/smt_xor_differential_model_test.py index 8dee7fe9..746e54af 100644 --- a/tests/unit/cipher_modules/models/smt/smt_models/smt_xor_differential_model_test.py +++ b/tests/unit/cipher_modules/models/smt/smt_models/smt_xor_differential_model_test.py @@ -41,7 +41,7 @@ def test_find_one_xor_differential_trail(): bit_positions=range(32), bit_values=integer_to_bit_list(0, 32, 'big')) solution = smt.find_one_xor_differential_trail(fixed_values=[plaintext]) - assert solution['cipher_id'] == 'speck_p32_k64_o32_r5' + assert str(solution['cipher']) == 'speck_p32_k64_o32_r5' assert solution['solver_name'] == 'z3' assert eval('0x' + solution['components_values']['intermediate_output_0_6']['value']) >= 0 assert solution['components_values']['intermediate_output_0_6']['weight'] == 0 diff --git a/tests/unit/cipher_modules/models/smt/smt_models/smt_xor_linear_model_test.py b/tests/unit/cipher_modules/models/smt/smt_models/smt_xor_linear_model_test.py index 99c0ffb6..196606d6 100644 --- a/tests/unit/cipher_modules/models/smt/smt_models/smt_xor_linear_model_test.py +++ b/tests/unit/cipher_modules/models/smt/smt_models/smt_xor_linear_model_test.py @@ -33,7 +33,7 @@ def test_find_one_xor_linear_trail(): bit_positions=range(32), bit_values=integer_to_bit_list(0, 32, 'big')) solution = smt.find_one_xor_linear_trail(fixed_values=[plaintext]) - assert solution['cipher_id'] == 'speck_p32_k64_o32_r4' + assert str(solution['cipher']) == 'speck_p32_k64_o32_r4' assert solution['solver_name'] == 'z3' assert eval('0x' + solution['components_values']['modadd_0_1_i']['value']) >= 0 assert solution['components_values']['modadd_0_1_i']['weight'] == 0 diff --git a/tests/unit/cipher_modules/neural_network_tests_test.py b/tests/unit/cipher_modules/neural_network_tests_test.py index b2d0840b..696cc291 100644 --- a/tests/unit/cipher_modules/neural_network_tests_test.py +++ b/tests/unit/cipher_modules/neural_network_tests_test.py @@ -47,13 +47,14 @@ def test_get_differential_dataset(): def test_neural_network_blackbox_distinguisher_tests(): cipher = SpeckBlockCipher(number_of_rounds=5) results = NeuralNetworkTests(cipher).neural_network_blackbox_distinguisher_tests(nb_samples=10) - assert results['input_parameters'] == {'number_of_samples': 10, 'hidden_layers': [32, 32, 32], 'number_of_epochs': 10, 'test_name': 'neural_network_blackbox_distinguisher_tests'} + assert results['input_parameters'] == {'cipher': cipher, 'number_of_samples': 10, 'hidden_layers': [32, 32, 32], 'number_of_epochs': 10, 'test_name': 'neural_network_blackbox_distinguisher_tests'} def test_neural_network_differential_distinguisher_tests(): cipher = SpeckBlockCipher(number_of_rounds=5) results = NeuralNetworkTests(cipher).neural_network_differential_distinguisher_tests(nb_samples=10) - assert results['input_parameters'] == {'test_name': 'neural_network_differential_distinguisher_tests', + assert results['input_parameters'] == {'cipher': cipher, + 'test_name': 'neural_network_differential_distinguisher_tests', 'number_of_samples': 10, 'input_differences': [[4194304], [10]], 'hidden_layers': [32, 32, 32], diff --git a/tests/unit/cipher_modules/report_test.py b/tests/unit/cipher_modules/report_test.py index 325ab5c8..bc579f4f 100644 --- a/tests/unit/cipher_modules/report_test.py +++ b/tests/unit/cipher_modules/report_test.py @@ -7,12 +7,13 @@ from claasp.ciphers.block_ciphers.simon_block_cipher import SimonBlockCipher from claasp.cipher_modules.report import Report from claasp.cipher_modules.statistical_tests.dieharder_statistical_tests import DieharderTests -from claasp.cipher_modules.statistical_tests.nist_statistical_tests import StatisticalTests +from claasp.cipher_modules.statistical_tests.nist_statistical_tests import NISTStatisticalTests from claasp.cipher_modules.neural_network_tests import NeuralNetworkTests from claasp.cipher_modules.algebraic_tests import AlgebraicTests from claasp.cipher_modules.avalanche_tests import AvalancheTests from claasp.cipher_modules.component_analysis_tests import CipherComponentsAnalysis + def test_save_as_image(): speck = SpeckBlockCipher(number_of_rounds=2) sat = SatXorDifferentialModel(speck) @@ -28,19 +29,19 @@ def test_save_as_image(): bit_values=(0,) * 64) trail = sat.find_lowest_weight_xor_differential_trail(fixed_values=[plaintext, key]) - trail_report = Report(speck, trail) + trail_report = Report(trail) trail_report.save_as_image() avalanche_results = AvalancheTests(speck).avalanche_tests() - avalanche_report = Report(speck, avalanche_results) + avalanche_report = Report(avalanche_results) avalanche_report.save_as_image() blackbox_results = NeuralNetworkTests(speck).neural_network_blackbox_distinguisher_tests() - blackbox_report = Report(speck, blackbox_results) + blackbox_report = Report(blackbox_results) blackbox_report.save_as_image() algebraic_results = AlgebraicTests(speck).algebraic_tests(timeout=1) - algebraic_report = Report(speck, algebraic_results) + algebraic_report = Report(algebraic_results) algebraic_report.save_as_image() @@ -62,16 +63,20 @@ def test_save_as_latex_table(): trail = smt.find_lowest_weight_xor_differential_trail(fixed_values=[plaintext, key]) avalanche_test_results = AvalancheTests(simon).avalanche_tests() - avalanche_report = Report(simon, avalanche_test_results) + avalanche_report = Report(avalanche_test_results) avalanche_report.save_as_latex_table() - trail_report = Report(simon, trail) + trail_report = Report(trail) trail_report.save_as_latex_table() + nist = NISTStatisticalTests(simon) + report_sts = Report(nist.nist_statistical_tests('avalanche')) + report_sts.save_as_latex_table() + def test_save_as_DataFrame(): speck = SpeckBlockCipher(number_of_rounds=2) - smt = CpXorDifferentialModel(speck) + cp = CpXorDifferentialModel(speck) plaintext = set_fixed_variables( component_id='plaintext', constraint_type='not_equal', @@ -82,25 +87,33 @@ def test_save_as_DataFrame(): constraint_type='equal', bit_positions=range(64), bit_values=(0,) * 64) - trail = smt.find_lowest_weight_xor_differential_trail(fixed_values=[plaintext, key]) + trail = cp.find_lowest_weight_xor_differential_trail(fixed_values=[plaintext, key]) algebraic_results = AlgebraicTests(speck).algebraic_tests(timeout=1) - algebraic_report = Report(speck, algebraic_results) + algebraic_report = Report(algebraic_results) algebraic_report.save_as_DataFrame() avalanche_results = AvalancheTests(speck).avalanche_tests() - avalanche_report = Report(speck,avalanche_results) + avalanche_report = Report(avalanche_results) avalanche_report.save_as_DataFrame() - trail_report = Report(speck, trail) + trail_report = Report(trail) trail_report.save_as_DataFrame() + nist = NISTStatisticalTests(speck) + report_sts = Report(nist.nist_statistical_tests('avalanche')) + report_sts.save_as_DataFrame() + def test_save_as_json(): simon = SimonBlockCipher(number_of_rounds=3) neural_network_blackbox_distinguisher_tests_results = NeuralNetworkTests( simon).neural_network_blackbox_distinguisher_tests() - blackbox_report = Report(simon, neural_network_blackbox_distinguisher_tests_results) + blackbox_report = Report(neural_network_blackbox_distinguisher_tests_results) + + nist = NISTStatisticalTests(simon) + report_sts = Report(nist.nist_statistical_tests('avalanche')) + report_sts.save_as_json() milp = MilpXorDifferentialModel(simon) plaintext = set_fixed_variables( @@ -116,14 +129,14 @@ def test_save_as_json(): trail = milp.find_lowest_weight_xor_differential_trail(fixed_values=[plaintext, key]) - trail_report = Report(simon, trail) + trail_report = Report(trail) algebraic_results = AlgebraicTests(simon).algebraic_tests(timeout=1) - algebraic_report = Report(simon, algebraic_results) + algebraic_report = Report(algebraic_results) algebraic_report.save_as_json() avalanche_results = AvalancheTests(simon).avalanche_tests() - avalanche_report = Report(simon,avalanche_results) + avalanche_report = Report(avalanche_results) avalanche_report.save_as_json() trail_report.save_as_json() @@ -134,25 +147,51 @@ def test_clean_reports(): simon = SimonBlockCipher(number_of_rounds=2) neural_network_blackbox_distinguisher_tests_results = NeuralNetworkTests( simon).neural_network_blackbox_distinguisher_tests() - blackbox_report = Report(simon, neural_network_blackbox_distinguisher_tests_results) + blackbox_report = Report(neural_network_blackbox_distinguisher_tests_results) blackbox_report.save_as_json() blackbox_report.clean_reports() -def test_show(): +def test_show(): speck = SpeckBlockCipher(number_of_rounds=3) component_analysis = CipherComponentsAnalysis(speck).component_analysis_tests() - report_cca = Report(speck,component_analysis) + report_cca = Report(component_analysis) report_cca.show() - - result = NeuralNetworkTests(speck).run_autond_pipeline(optimizer_samples=10 ** 3, optimizer_generations=1, - training_samples=10 ** 2, testing_samples=10 ** 2, - number_of_epochs=1, verbose=False) - report_autond = Report(speck,result) - report_autond.show() + #result = NeuralNetworkTests(speck).run_autond_pipeline(optimizer_samples=10 ** 3, optimizer_generations=1, + # training_samples=10 ** 2, testing_samples=10 ** 2, + # number_of_epochs=1, verbose=False) + #report_autond = Report(result) + #report_autond.show() avalanche_results = AvalancheTests(speck).avalanche_tests() - avalanche_report = Report(speck,avalanche_results) - avalanche_report.show() \ No newline at end of file + avalanche_report = Report(avalanche_results) + avalanche_report.show(test_name=None) + avalanche_report.show(test_name='avalanche_weight_vectors', fixed_input_difference=None) + avalanche_report.show(test_name='avalanche_weight_vectors', fixed_input_difference='average') + + milp = MilpXorDifferentialModel(speck) + plaintext = set_fixed_variables( + component_id='plaintext', + constraint_type='not_equal', + bit_positions=range(32), + bit_values=(0,) * 32) + key = set_fixed_variables( + component_id='key', + constraint_type='equal', + bit_positions=range(64), + bit_values=(0,) * 64) + + trail = milp.find_one_xor_differential_trail(fixed_values=[plaintext, key]) + trail_report = Report(trail) + trail_report.show() + + nist = NISTStatisticalTests(speck) + report_sts = Report(nist.nist_statistical_tests('avalanche')) + report_sts.show() + + neural_network_tests = NeuralNetworkTests(speck).neural_network_differential_distinguisher_tests() + neural_network_tests_report = Report(neural_network_tests) + neural_network_tests_report.show(fixed_input_difference=None) + neural_network_tests_report.show(fixed_input_difference='0xa') \ No newline at end of file diff --git a/tests/unit/cipher_modules/statistical_tests/nist_statistical_tests_test.py b/tests/unit/cipher_modules/statistical_tests/nist_statistical_tests_test.py index e75ad710..6dc1e11f 100644 --- a/tests/unit/cipher_modules/statistical_tests/nist_statistical_tests_test.py +++ b/tests/unit/cipher_modules/statistical_tests/nist_statistical_tests_test.py @@ -3,7 +3,7 @@ from io import StringIO import pytest from claasp.ciphers.block_ciphers.simon_block_cipher import SimonBlockCipher -from claasp.cipher_modules.statistical_tests.nist_statistical_tests import StatisticalTests +from claasp.cipher_modules.statistical_tests.nist_statistical_tests import NISTStatisticalTests REPORT_EXAMPLE_TXT = 'claasp/cipher_modules/statistical_tests/finalAnalysisReportExample.txt' @@ -12,14 +12,14 @@ def test_run_nist_statistical_tests_tool(): if os.path.exists('test_reports/statistical_tests/experiments'): os.removedirs('test_reports/statistical_tests/experiments') os.makedirs('test_reports/statistical_tests/experiments') - result = StatisticalTests._run_nist_statistical_tests_tool( + result = NISTStatisticalTests._run_nist_statistical_tests_tool( 'claasp/cipher_modules/statistical_tests/input_data_example', 10000, 10, 1) assert result is True def test_parse_report(): - dictio = StatisticalTests._parse_report(REPORT_EXAMPLE_TXT) + dictio = NISTStatisticalTests._parse_report(REPORT_EXAMPLE_TXT) assert dictio['number_of_sequences_threshold'] == [{'total': 10, 'passed': 8}, {'total': 8, 'passed': 7}] assert dictio['randomness_test'][0]['test_id'] == 1 @@ -27,7 +27,7 @@ def test_parse_report(): def test_generate_chart_round(): - dictio = StatisticalTests._parse_report(REPORT_EXAMPLE_TXT) + dictio = NISTStatisticalTests._parse_report(REPORT_EXAMPLE_TXT) dictio['data_type'] = 'random' dictio['cipher_name'] = 'toy_cipher' dictio['round'] = 1 @@ -36,7 +36,7 @@ def test_generate_chart_round(): old_stdout = sys.stdout result = StringIO() sys.stdout = result - StatisticalTests.generate_chart_round(dictio) + NISTStatisticalTests._generate_chart_round(dictio) sys.stdout = old_stdout assert result.getvalue() == \ @@ -45,7 +45,7 @@ def test_generate_chart_round(): def test_generate_chart_all(): - dictio = StatisticalTests._parse_report(REPORT_EXAMPLE_TXT) + dictio = NISTStatisticalTests._parse_report(REPORT_EXAMPLE_TXT) dictio['data_type'] = 'random' dictio['cipher_name'] = 'toy_cipher' dictio['round'] = 1 @@ -55,12 +55,12 @@ def test_generate_chart_all(): old_stdout = sys.stdout result = StringIO() sys.stdout = result - StatisticalTests.generate_chart_all(dict_list) + NISTStatisticalTests._generate_chart_all(dict_list) sys.stdout = old_stdout def test_run_avalanche_nist_statistics_test(): - tests = StatisticalTests(SimonBlockCipher(number_of_rounds=1)) + tests = NISTStatisticalTests(SimonBlockCipher(number_of_rounds=1)) old_stdout = sys.stdout result = StringIO() sys.stdout = result @@ -70,7 +70,7 @@ def test_run_avalanche_nist_statistics_test(): assert return_str.find('Finished.') == len(return_str) - 10 def test_run_correlation_nist_statistics_test(): - tests = StatisticalTests(SimonBlockCipher(number_of_rounds=1)) + tests = NISTStatisticalTests(SimonBlockCipher(number_of_rounds=1)) old_stdout = sys.stdout result = StringIO() sys.stdout = result @@ -82,7 +82,7 @@ def test_run_correlation_nist_statistics_test(): @pytest.mark.skip("Takes too long") def test_run_CBC_nist_statistics_test(): - tests = StatisticalTests(SimonBlockCipher(number_of_rounds=1)) + tests = NISTStatisticalTests(SimonBlockCipher(number_of_rounds=1)) old_stdout = sys.stdout result = StringIO() sys.stdout = result @@ -93,7 +93,7 @@ def test_run_CBC_nist_statistics_test(): def test_run_random_nist_statistics_test(): - tests = StatisticalTests(SimonBlockCipher(number_of_rounds=1)) + tests = NISTStatisticalTests(SimonBlockCipher(number_of_rounds=1)) old_stdout = sys.stdout result = StringIO() sys.stdout = result @@ -103,7 +103,7 @@ def test_run_random_nist_statistics_test(): assert return_str.find('Finished.') == len(return_str) - 10 def test_run_low_density_nist_statistics_test(): - tests = StatisticalTests(SimonBlockCipher(number_of_rounds=1)) + tests = NISTStatisticalTests(SimonBlockCipher(number_of_rounds=1)) old_stdout = sys.stdout result = StringIO() sys.stdout = result @@ -113,7 +113,7 @@ def test_run_low_density_nist_statistics_test(): assert return_str.find('Finished.') == len(return_str) - 10 def test_run_high_density_nist_statistics_test(): - tests = StatisticalTests(SimonBlockCipher(number_of_rounds=1)) + tests = NISTStatisticalTests(SimonBlockCipher(number_of_rounds=1)) old_stdout = sys.stdout result = StringIO() sys.stdout = result diff --git a/tests/unit/cipher_test.py b/tests/unit/cipher_test.py index c6d3123a..104773bc 100644 --- a/tests/unit/cipher_test.py +++ b/tests/unit/cipher_test.py @@ -51,35 +51,37 @@ def test_algebraic_tests(): toyspn = ToySPN1(number_of_rounds=2) - d = AlgebraicTests(toyspn).algebraic_tests(30) + d = AlgebraicTests(toyspn).algebraic_tests(10) assert d == { - 'input_parameters': {'cipher.id': 'toyspn1_p6_k6_o6_r2', 'timeout': 30, 'test_name': 'algebraic_tests'}, + 'input_parameters': {'cipher': toyspn, 'timeout': 10, 'test_name': 'algebraic_tests'}, 'test_results': {'number_of_variables': [66, 126], 'number_of_equations': [76, 158], 'number_of_monomials': [96, 186], 'max_degree_of_equations': [2, 2], - 'test_passed': [False, False]}} - - speck = SpeckBlockCipher(block_bit_size=32, key_bit_size=64, number_of_rounds=2) - d = AlgebraicTests(speck).algebraic_tests(5) - assert d == { - 'input_parameters': {'cipher.id': 'speck_p32_k64_o32_r2', 'timeout': 5, 'test_name': 'algebraic_tests'}, - 'test_results': {'number_of_variables': [304, 800], - 'number_of_equations': [240, 688], - 'number_of_monomials': [304, 800], - 'max_degree_of_equations': [1, 1], - 'test_passed': [False, False]}} - - aes = AESBlockCipher(word_size=4, state_size=2, number_of_rounds=2) + 'test_passed': [False, True]}} + + speck = SpeckBlockCipher(block_bit_size=32, key_bit_size=64, number_of_rounds=1) + d = AlgebraicTests(speck).algebraic_tests(1) + assert d == {'input_parameters': {'cipher': speck, + 'timeout': 1, + 'test_name': 'algebraic_tests'}, + 'test_results': {'number_of_variables': [320], + 'number_of_equations': [272], + 'number_of_monomials': [365], + 'max_degree_of_equations': [2], + 'test_passed': [True]}} + + aes = AESBlockCipher(word_size=4, state_size=2, number_of_rounds=1) d = AlgebraicTests(aes).algebraic_tests(5) - compare_result = {'input_parameters': {'cipher.id': 'aes_block_cipher_k16_p16_o16_r2', - 'timeout': 5, - 'test_name': 'algebraic_tests'}, - 'test_results': {'number_of_variables': [352, 592], - 'number_of_equations': [454, 796], - 'number_of_monomials': [520, 928], - 'max_degree_of_equations': [2, 2], - 'test_passed': [False, False]}} + compare_result = {'input_parameters': {'cipher': aes, + 'timeout': 5, + 'test_name': 'algebraic_tests'}, + 'test_results': {'number_of_variables': [320], + 'number_of_equations': [390], + 'number_of_monomials': [488], + 'max_degree_of_equations': [2], + 'test_passed': [False]}} + assert d == compare_result