Skip to content

Commit

Permalink
Merge pull request #234 from Crypto-TII/develop
Browse files Browse the repository at this point in the history
May 2024 Release
  • Loading branch information
peacker authored May 22, 2024
2 parents e8bdc21 + 3596702 commit 339c976
Show file tree
Hide file tree
Showing 138 changed files with 2,845 additions and 1,037 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/build-claasp-base-image.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
name: Build and push image for testing
on:
pull_request:
types: [ closed ]
push:
branches:
- main

Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/build-main-webapp-image.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
name: Build and push image from main
on:
pull_request:
types: [ closed ]
push:
branches:
- main

Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/build-staging-webapp-image.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
name: Build and push image from develop
on:
pull_request:
types: [ closed ]
push:
branches:
- develop

Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/generate-and-submit-documentation.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
name: Generate and submit documentation
on:
pull_request:
types: [ closed ]
push:
branches:
- main

Expand Down
5 changes: 1 addition & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ rundocker: builddocker
sh -c "cd /home/sage/tii-claasp && make install && cd /home/sage/tii-claasp && exec /bin/bash"

builddocker-m1:
docker build --build-arg="GUROBI_ARCH=armlinux64" -f docker/Dockerfile --platform linux/aarch64 --target claasp-base -t $(DOCKER_IMG_NAME) .
docker build -f docker/Dockerfile --platform linux/x86_64 --target claasp-base -t $(DOCKER_IMG_NAME) .

rundocker-m1: builddocker-m1
docker run -i -p 8888:8888 --mount type=bind,source=`pwd`,target=/home/sage/tii-claasp -t $(DOCKER_IMG_NAME) \
Expand Down Expand Up @@ -95,6 +95,3 @@ copyright: install

local-installation:
./configure.sh

local-installation-m1:
./configure.sh armlinux64
13 changes: 8 additions & 5 deletions claasp/cipher.py
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,7 @@ def cipher_partial_inverse(self, start_round=None, end_round=None, keep_key_sche

return partial_cipher_inverse

def evaluate_vectorized(self, cipher_input, intermediate_outputs=False, verbosity=False):
def evaluate_vectorized(self, cipher_input, intermediate_output=False, verbosity=False, evaluate_api = False, bit_based = False):
"""
Return the output of the cipher for multiple inputs.
Expand All @@ -766,10 +766,12 @@ def evaluate_vectorized(self, cipher_input, intermediate_outputs=False, verbosit
- ``cipher_input`` -- **list**; block cipher inputs (ndarray of uint8 representing one byte each, n rows, m columns,
with m the number of inputs to evaluate)
- ``intermediate_outputs`` -- **boolean** (default: `False`)
- ``intermediate_output`` -- **boolean** (default: `False`)
- ``verbosity`` -- **boolean** (default: `False`); set this flag to True in order to print the input/output of
each component
- ``evaluate_api`` -- **boolean** (default: `False`); if set to True, takes integer inputs (as the evaluate function)
and returns integer inputs; it is expected that cipher.evaluate(x) == cipher.evaluate_vectorized(x, evaluate_api = True)
is True.
EXAMPLES::
sage: import numpy as np
Expand All @@ -789,7 +791,7 @@ def evaluate_vectorized(self, cipher_input, intermediate_outputs=False, verbosit
sage: int.from_bytes(result[-1][1].tobytes(), byteorder='big') == C1Lib
True
"""
return evaluator.evaluate_vectorized(self, cipher_input, intermediate_outputs, verbosity)
return evaluator.evaluate_vectorized(self, cipher_input, intermediate_output, verbosity, evaluate_api, bit_based)

def evaluate_with_intermediate_outputs_continuous_diffusion_analysis(
self, cipher_input, sbox_precomputations, sbox_precomputations_mix_columns, verbosity=False):
Expand Down Expand Up @@ -1708,4 +1710,5 @@ def get_descendants_subgraph(G, start_nodes):

def update_input_id_links_from_component_id(self, component_id, new_input_id_links):
round_number = self.get_round_from_component_id(component_id)
self._rounds.rounds[round_number].update_input_id_links_from_component_id(component_id, new_input_id_links)
self._rounds.rounds[round_number].update_input_id_links_from_component_id(component_id, new_input_id_links)

23 changes: 13 additions & 10 deletions claasp/cipher_modules/algebraic_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ class AlgebraicTests:
{'input_parameters': {'cipher': toyspn1_p6_k6_o6_r2,
'timeout_in_seconds': 10,
'test_name': 'algebraic_tests'},
'test_results': {'number_of_variables': [30, 48],
'number_of_equations': [40, 80],
'number_of_monomials': [60, 108],
'test_results': {'number_of_variables': [24, 42],
'number_of_equations': [34, 74],
'number_of_monomials': [54, 102],
'max_degree_of_equations': [2, 2],
'test_passed': [False, False]}}
Expand All @@ -48,9 +48,9 @@ class AlgebraicTests:
{'input_parameters': {'cipher': speck_p32_k64_o32_r1,
'timeout_in_seconds': 30,
'test_name': 'algebraic_tests'},
'test_results': {'number_of_variables': [144],
'number_of_equations': [96],
'number_of_monomials': [189],
'test_results': {'number_of_variables': [112],
'number_of_equations': [64],
'number_of_monomials': [157],
'max_degree_of_equations': [2],
'test_passed': [True]}}
Expand All @@ -69,12 +69,15 @@ def algebraic_tests(self, timeout_in_seconds=60):
tests_up_to_round = []

F = []
constant_vars = {}
dict_vars = {}
for round_number in range(self._cipher.number_of_rounds):
F += self._algebraic_model.polynomial_system_at_round(round_number, True)
constant_vars.update(self._algebraic_model._dict_constant_component_polynomials(round_number))
if constant_vars is not None:
F = self._algebraic_model._remove_constant_polynomials(constant_vars, F)
dict_vars.update(self._algebraic_model._dict_const_rot_not_shift_component_polynomials(round_number))
if round_number == self._cipher.number_of_rounds - 1 and dict_vars:
dict_vars = self._algebraic_model._substitute_cipher_output_vars_dict_vars(dict_vars, round_number)
if dict_vars:
F = self._algebraic_model._eliminate_const_not_shift_rot_components_polynomials(dict_vars, F)

Fseq = Sequence(F)
nvars_up_to_round.append(Fseq.nvariables())
npolynomials_up_to_round.append(len(Fseq))
Expand Down
4 changes: 2 additions & 2 deletions claasp/cipher_modules/avalanche_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ def avalanche_probability_vectors(self, nb_samples):
all_avalanche_probability_vectors[cipher_input][intermediate_output_name] = []

inputs = self._generate_random_inputs(nb_samples)
evaluated_inputs = evaluator.evaluate_vectorized(self._cipher, inputs, intermediate_outputs=True, verbosity=False)
evaluated_inputs = evaluator.evaluate_vectorized(self._cipher, inputs, intermediate_output=True, verbosity=False)
input_bits_to_analyse = self._cipher.get_all_inputs_bit_positions()
for index_of_specific_input, specific_input in enumerate(self._cipher.inputs): # where the diff is injected
for input_diff in input_bits_to_analyse[specific_input]:
Expand All @@ -323,7 +323,7 @@ def _generate_avalanche_probability_vectors(self, dict_intermediate_output_names
evaluated_inputs, input_diff, index_of_specific_input):
inputs_prime = self._generate_inputs_prime(index_of_specific_input, input_diff, inputs)
evaluated_inputs_prime = evaluator.evaluate_vectorized(self._cipher, inputs_prime,
intermediate_outputs=True, verbosity=False)
intermediate_output=True, verbosity=False)
intermediate_avalanche_probability_vectors = {}
for intermediate_output_name in list(dict_intermediate_output_names.keys()):
intermediate_avalanche_probability_vectors[intermediate_output_name] = \
Expand Down
97 changes: 74 additions & 23 deletions claasp/cipher_modules/code_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from claasp.name_mappings import (SBOX, LINEAR_LAYER, MIX_COLUMN, WORD_OPERATION, CONSTANT,
CONCATENATE, PADDING, INTERMEDIATE_OUTPUT, CIPHER_OUTPUT,
FSR, CIPHER_INVERSE_SUFFIX)

from claasp.cipher_modules.generic_functions_vectorized_byte import get_number_of_bytes_needed_for_bit_size
tii_path = inspect.getfile(claasp)
tii_dir_path = os.path.dirname(tii_path)

Expand Down Expand Up @@ -219,7 +219,6 @@ def get_word_operation_component_bit_based_c_code(component, verbosity):

return word_operation_code


def generate_bit_based_vectorized_python_code_string(cipher, store_intermediate_outputs=False,
verbosity=False, convert_output_to_bytes=False):
"""
Expand Down Expand Up @@ -257,8 +256,62 @@ def generate_bit_based_vectorized_python_code_string(cipher, store_intermediate_
component.description[0] in component_descriptions_allowed):
code.extend(component.get_bit_based_vectorized_python_code(params, convert_output_to_bytes))
name = component.id
if True and component.type != 'constant':
code.append(f' bit_vector_print_as_hex_values("{name}_output", {name})')
if store_intermediate_outputs:
code.append(' return intermediateOutputs')
elif CIPHER_INVERSE_SUFFIX in cipher.id:
code.append(' return intermediateOutputs["plaintext"]')
else:
code.append(' return intermediateOutputs["cipher_output"]')

return '\n'.join(code)


def generate_bit_based_vectorized_python_code_string(cipher, store_intermediate_outputs=False,
verbosity=False, convert_output_to_bytes=False):
"""
Return string python code needed to evaluate a cipher using a vectorized implementation bit based oriented.
INPUT:
- ``cipher`` -- **Cipher object**; a cipher instance
- ``store_intermediate_outputs`` -- **boolean** (default: `False`); set this flag to True in order to return a list
with each round output
- ``verbosity`` -- **boolean** (default: `False`); set to True to make the Python code print the input/output of
each component
- ``convert_output_to_bytes`` -- **boolean** (default: `False`)
EXAMPLES::
sage: from claasp.ciphers.block_ciphers.speck_block_cipher import SpeckBlockCipher
sage: from claasp.cipher_modules import code_generator
sage: speck = SpeckBlockCipher()
sage: string_python_code = code_generator.generate_bit_based_vectorized_python_code_string(speck)
sage: string_python_code.split("\n")[0]
'from claasp.cipher_modules.generic_functions_vectorized_bit import *'
"""
code = ['from claasp.cipher_modules.generic_functions_vectorized_bit import *\n',
'from time import time \n'
'def evaluate(input, store_intermediate_outputs):', ' intermediateOutputs={}']
code.extend([f' {cipher.inputs[i]}=input[{i}]' for i in range(len(cipher.inputs))])
for component in cipher.get_all_components():
params = prepare_input_bit_based_vectorized_python_code_string(component)
component_types_allowed = ['constant', 'linear_layer', 'concatenate', 'mix_column',
'sbox', 'cipher_output', 'intermediate_output', 'fsr']
component_descriptions_allowed = ['ROTATE', 'SHIFT', 'SHIFT_BY_VARIABLE_AMOUNT', 'NOT', 'XOR',
'MODADD', 'MODSUB', 'OR', 'AND']
if component.type in component_types_allowed or (component.type == 'word_operation' and
component.description[0] in component_descriptions_allowed):
code.append(" t0 = time()")
code.extend(component.get_bit_based_vectorized_python_code(params, convert_output_to_bytes))
name = component.id
#code.append(f" print('{name}', {name}.dtype)")
code.append(f" print('{name}', time()-t0)")

if verbosity and component.type != 'constant':
code.append(f' bit_vector_print_as_hex_values("{name}_output", {name})')

if store_intermediate_outputs:
code.append(' return intermediateOutputs')
elif CIPHER_INVERSE_SUFFIX in cipher.id:
Expand Down Expand Up @@ -286,7 +339,7 @@ def constant_to_bitstring(val, output_size):
return ret


def generate_byte_based_vectorized_python_code_string(cipher, store_intermediate_outputs=False, verbosity=False):
def generate_byte_based_vectorized_python_code_string(cipher, store_intermediate_outputs=False, verbosity=False, integers_inputs_and_outputs = False):
r"""
Return string python code needed to evaluate a cipher using a vectorized implementation byte based oriented.
Expand All @@ -309,34 +362,41 @@ def generate_byte_based_vectorized_python_code_string(cipher, store_intermediate
"""
cipher.sort_cipher()

code = ['from claasp.cipher_modules.generic_functions_vectorized_byte import *\n', '\n',
code = ['from claasp.cipher_modules.generic_functions_vectorized_byte import *\n',
'integers_inputs_and_outputs='+str(integers_inputs_and_outputs)+'\n',
'def evaluate(input, store_intermediate_outputs):', ' intermediateOutputs={}']
bit_sizes = {}
output_bit_sizes = {}
code.append(' if integers_inputs_and_outputs:\n'
' input = cipher_inputs_to_evaluate_vectorized_inputs(input, ' + str(cipher.inputs_bit_size) + ')')
for i in range(len(cipher.inputs)):
code.append(f' {cipher.inputs[i]}=input[{i}]')
bit_sizes[cipher.inputs[i]] = cipher.inputs_bit_size[i]
output_bit_sizes[cipher.inputs[i]] = cipher.inputs_bit_size[i]
for component in cipher.get_all_components():
params = prepare_input_byte_based_vectorized_python_code_string(bit_sizes, component)
bit_sizes[component.id] = component.output_bit_size
#code.append(f' print("{component.id}")')
formatted_component_inputs = prepare_input_byte_based_vectorized_python_code_string(output_bit_sizes, component)
output_bit_sizes[component.id] = component.output_bit_size
component_types_allowed = ['constant', 'linear_layer', 'concatenate', 'mix_column',
'sbox', 'cipher_output', 'intermediate_output', 'fsr']
component_descriptions_allowed = ['ROTATE', 'SHIFT', 'SHIFT_BY_VARIABLE_AMOUNT', 'NOT', 'XOR',
'MODADD', 'MODSUB', 'OR', 'AND']
if component.type in component_types_allowed or (component.type == 'word_operation' and
component.description[0] in component_descriptions_allowed):
code.extend(component.get_byte_based_vectorized_python_code(params))
code.extend(component.get_byte_based_vectorized_python_code(formatted_component_inputs))

name = component.id

if verbosity and component.type != 'constant':
code.append(f' byte_vector_print_as_hex_values("{name}_input", {params})')
code.append(f' byte_vector_print_as_hex_values("{name}_input", {formatted_component_inputs})')
code.append(f' byte_vector_print_as_hex_values("{name}_output", {name})')
#code.append(' print("CIPHER OUTPUT : ", cipher_output_15_15)')

if store_intermediate_outputs:
code.append(' return intermediateOutputs')
elif CIPHER_INVERSE_SUFFIX in cipher.id:
code.append(' return intermediateOutputs["plaintext"]')
else:
code.append(' return intermediateOutputs["cipher_output"]')
# print('\n'.join(code))

return '\n'.join(code)

Expand All @@ -350,8 +410,10 @@ def prepare_input_byte_based_vectorized_python_code_string(bit_sizes, component)
if component.type == 'constant':
return params

#assert (input_bit_size % number_of_inputs) == 0, f"The number of inputs does not divide the number of input bits " \
# f"for component {component.id}. "
bits_per_input = input_bit_size // number_of_inputs
words_per_input = math.ceil(bits_per_input / 8)
words_per_input = get_number_of_bytes_needed_for_bit_size(bits_per_input)
# Divide inputs
real_inputs = [[] for _ in range(number_of_inputs)]
real_bits = [[] for _ in range(number_of_inputs)]
Expand Down Expand Up @@ -407,7 +469,7 @@ def get_number_of_inputs(component):
else:
number_of_inputs = component.description[1]
elif component.type == 'mix_column':
number_of_inputs = len(component.description[0])
number_of_inputs = len(component.description[0][0])
elif component.type == 'linear_layer':
number_of_inputs = len(component.description[0])
elif component.type == 'sbox':
Expand All @@ -420,17 +482,6 @@ def get_number_of_inputs(component):
return number_of_inputs


def constant_to_repr(val, output_size):
_val = int(val, 0)
if output_size % 8 != 0:
s = output_size + (8 - (output_size % 8))
else:
s = output_size
ret = [(_val >> s - (8 * (i + 1))) & 0xff for i in range(s // 8)]

return ret


def generate_evaluate_c_code_shared_library(cipher, intermediate_output, verbosity):
name = cipher.id + "_evaluate"
cipher_word_size = cipher.is_power_of_2_word_based()
Expand Down
30 changes: 11 additions & 19 deletions claasp/cipher_modules/evaluator.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

# ****************************************************************************
# Copyright 2023 Technology Innovation Institute
#
Expand All @@ -22,11 +21,13 @@
from subprocess import Popen, PIPE

from claasp.cipher_modules import code_generator
from claasp.cipher_modules.generic_functions_vectorized_byte import cipher_inputs_to_evaluate_vectorized_inputs, \
evaluate_vectorized_outputs_to_integers


def evaluate(cipher, cipher_input, intermediate_output=False, verbosity=False):
python_code_string = code_generator.generate_python_code_string(cipher, verbosity)

f_module = ModuleType("evaluate")
exec(python_code_string, f_module.__dict__)

Expand Down Expand Up @@ -77,25 +78,16 @@ def evaluate_using_c(cipher, inputs, intermediate_output, verbosity):
return function_output


def evaluate_vectorized(cipher, cipher_input, intermediate_outputs=False, verbosity=False):
if np.any(np.array(cipher.inputs_bit_size) % 8 != 0):
python_code_string = code_generator \
.generate_bit_based_vectorized_python_code_string(cipher,
store_intermediate_outputs=intermediate_outputs,
verbosity=verbosity,
convert_output_to_bytes=True)
cipher_input = [np.unpackbits(cipher_input[i], axis=0)[:x, ]
for i, x in enumerate(cipher.inputs_bit_size)]
else:
python_code_string = code_generator \
.generate_byte_based_vectorized_python_code_string(
cipher,
store_intermediate_outputs=intermediate_outputs, verbosity=verbosity)

def evaluate_vectorized(cipher, cipher_input, intermediate_output=False, verbosity=False, evaluate_api=False,
bit_based=False):
python_code_string = code_generator.generate_byte_based_vectorized_python_code_string(cipher,
store_intermediate_outputs=intermediate_output,
verbosity=verbosity,
integers_inputs_and_outputs=evaluate_api)
f_module = ModuleType("evaluate")
exec(python_code_string, f_module.__dict__)

return f_module.evaluate(cipher_input, intermediate_outputs)
cipher_output = f_module.evaluate(cipher_input, intermediate_output)
return cipher_output


def evaluate_with_intermediate_outputs_continuous_diffusion_analysis(cipher, cipher_input, sbox_precomputations,
Expand Down
Loading

0 comments on commit 339c976

Please sign in to comment.