Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
0f726b9
Adding fsr_component.py, implement algebraic_polynomials method
May 3, 2023
51155a6
adding fsr evaluate function in generic_functions.py
May 8, 2023
f3e0f9b
fsr evaluation function debug
May 9, 2023
30e569a
adding fsr component method to cipher.py code_generator.py editor.py
May 10, 2023
9223684
debugging of evaluation function
May 23, 2023
d4aa9d9
temporarily commited
Jul 6, 2023
c8fcc4b
FIX/fix: fix the bug of the nist_statistical_tests_test.py when the e…
Jul 13, 2023
447c2af
Revise FSR with word size, debug, redefine the description: in progress
Jul 20, 2023
7b49f5f
Revise FSR with word size, debug, redefine the description: in progress
Jul 25, 2023
a3e53b8
temporarily updated
Jul 31, 2023
f44c441
temporarily updated for fsr_binary
Aug 2, 2023
bc63569
temporarily updated for fsr_word
Aug 4, 2023
c3fe0ef
temporarily updated for fsr_word
Aug 4, 2023
d987621
temporarily updated for a51
Aug 10, 2023
2242d0c
a51
Aug 15, 2023
6c1f020
updated of a5_1
Sep 13, 2023
19f73bb
updated of a5_2
Sep 13, 2023
6d74b60
Merge remote-tracking branch 'origin/develop' into develop
Sep 13, 2023
817a528
Merge branch 'develop' into LIBCA-1117-add-fsr-component
Sep 13, 2023
493b879
updated of lfsr component
Sep 18, 2023
5a6f924
modified fsr component
Sep 25, 2023
2de86bf
Merge branch 'develop' into feat-fsr_component_and_stream_ciphers
Sep 25, 2023
e985f2d
added trivium stream cipher
Sep 25, 2023
047310c
updated of lfsr component
Sep 25, 2023
8b3493c
Merge remote-tracking branch 'origin/develop' into develop
Sep 25, 2023
2e576ec
Merge branch 'develop' into LIBCA-1117-add-fsr-component
Sep 25, 2023
d798c79
Merge remote-tracking branch 'origin/feat-fsr_component_and_stream_ci…
Sep 25, 2023
3573cd0
added bivium stream cipher and test for trivium stream cipher
Sep 26, 2023
d57061c
added a test vector for bivium stream cipher
Sep 26, 2023
2510cbb
Merge branch 'develop' into feat-fsr_component_and_stream_ciphers
Sep 26, 2023
0cec4da
Merge remote-tracking branch 'origin/feat-fsr_component_and_stream_ci…
Sep 27, 2023
a76d8e1
minor polishing on fsr component and trivium stream cipher
Sep 27, 2023
5890fda
Merge remote-tracking branch 'origin/feat-fsr_component_and_stream_ci…
Sep 27, 2023
d094d94
updated of a51
Oct 3, 2023
9267fcd
rename branch name
Oct 10, 2023
8d48927
FEATURE/Add: adding FSR component to the cipher.
Oct 10, 2023
c3871ff
clean branch
Oct 11, 2023
a018654
added bivium stream cipher and modified fsr component
Oct 12, 2023
83f71a9
Merge remote-tracking branch 'origin/develop' into LIBCA-1117-add-fsr…
Oct 12, 2023
cda06e6
Merge remote-tracking branch 'origin/feat/fsr_component_and_bivium_st…
Nov 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions claasp/cipher.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@ def add_concatenate_component(self, input_id_links, input_bit_positions, output_
def add_constant_component(self, output_bit_size, value):
return editor.add_constant_component(self, output_bit_size, value)

def add_FSR_component(self, input_id_links, input_bit_positions, output_bit_size, description):
return editor.add_FSR_component(self, input_id_links, input_bit_positions, output_bit_size, description)

def add_intermediate_output_component(self, input_id_links, input_bit_positions, output_bit_size, output_tag):
return editor.add_intermediate_output_component(self, input_id_links, input_bit_positions,
output_bit_size, output_tag)
Expand Down
18 changes: 15 additions & 3 deletions claasp/cipher_modules/code_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
import claasp
from claasp.component import free_input
from claasp.name_mappings import (SBOX, LINEAR_LAYER, MIX_COLUMN, WORD_OPERATION, CONSTANT,
CONCATENATE, PADDING, INTERMEDIATE_OUTPUT, CIPHER_OUTPUT)
CONCATENATE, PADDING, INTERMEDIATE_OUTPUT, CIPHER_OUTPUT,
FSR)

tii_path = inspect.getfile(claasp)
tii_dir_path = os.path.dirname(tii_path)
Expand Down Expand Up @@ -248,7 +249,7 @@ def generate_bit_based_vectorized_python_code_string(cipher, store_intermediate_
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']
'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
Expand Down Expand Up @@ -315,7 +316,7 @@ def generate_byte_based_vectorized_python_code_string(cipher, store_intermediate
params = prepare_input_byte_based_vectorized_python_code_string(bit_sizes, component)
bit_sizes[component.id] = component.output_bit_size
component_types_allowed = ['constant', 'linear_layer', 'concatenate', 'mix_column',
'sbox', 'cipher_output', 'intermediate_output']
'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
Expand Down Expand Up @@ -633,6 +634,17 @@ def build_function_call(component):
return "component_input"
elif component.type == PADDING:
return "padding(component_input)"
elif component.type == FSR:
registers_info = component.description[0]
bits_inside_word = component.description[1]
if len(component.description) is 2:
number_of_clocks = 1
else:
number_of_clocks = component.description[2]
if bits_inside_word == 1:
return f"fsr_binary(component_input, {registers_info}, {number_of_clocks})"
else:
return f"fsr_word(component_input, {registers_info}, {bits_inside_word}, {number_of_clocks})"
elif component.type == INTERMEDIATE_OUTPUT:
return "component_input"
elif component.type == CIPHER_OUTPUT:
Expand Down
186 changes: 182 additions & 4 deletions claasp/cipher_modules/generic_functions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

# ****************************************************************************
# Copyright 2023 Technology Innovation Institute
#
Expand Down Expand Up @@ -32,7 +31,6 @@
from claasp.utils.utils import int_to_poly, poly_to_int
from claasp.cipher_modules.models.algebraic.boolean_polynomial_ring import BooleanPolynomialRing


number_of_inputs_expression = " #in = {}"
input_expression = " in = {}"
output_expression = " out = {}"
Expand Down Expand Up @@ -223,6 +221,7 @@ def convert_x_to_binary_matrix_given_polynomial_modulus(word_size, polynomial):

- Binary matrix.
"""

def rot1_right(input_list):
tmp = input_list[len(input_list) - 1]
return [tmp] + input_list[:len(input_list) - 1]
Expand Down Expand Up @@ -407,8 +406,9 @@ def XOR_boolean_function(component, BoolPolyRing):
if component.input_id_links[i] not in variables_names_positions:
variables_names_positions[component.input_id_links[i]] = [tmp, component.input_bit_positions[i]]
else: # Keys are unique in a python dico, so need to handle 2 same entries in input_id_links !
variables_names_positions[component.input_id_links[i]] = [variables_names_positions[component.input_id_links[i]]
[0] + tmp, variables_names_positions[component.input_id_links[i]][1] + component.input_bit_positions[i]]
variables_names_positions[component.input_id_links[i]] = [
variables_names_positions[component.input_id_links[i]]
[0] + tmp, variables_names_positions[component.input_id_links[i]][1] + component.input_bit_positions[i]]

component_as_BF = []
tmp = 0
Expand Down Expand Up @@ -951,3 +951,181 @@ def select_bits(input, bit_positions, verbosity=False):

def merge_bits():
return 0


def fsr_binary(input, registers_info, number_of_clocks, verbosity=False):
"""
INPUT:

- ``input`` -- **BitArray object**; a BitArray
- ``registers_info`` -- **list**; a list of [register_bit_length, register_polynomial, clock_polynomial (optional)],
register_bit_length is an integer to indicates the length of register. register_polynomial and clock_polynomial
are lists of monomials, which is presented in the integer list. For example [[0], [1], [2, 3]] represents
x0+x1+x2*x3. [] represents 1.
- ``number_of_clocks`` -- **integer**; indicates how many loops this fsr component would operate, this is optional
by default it is 1.
- ``verbosity`` -- **boolean** (default: `False`); set this flag to True to print the input/output
"""

def get_polynomail(polynomial_index_list, R):
if polynomial_index_list == []:
return R(1)
p = 0
x = R.gens()
for _ in polynomial_index_list:
m = 1
for i in _:
m = m * x[i]
p += m
return p

output = BitArray(input)
R = BooleanPolynomialRing(len(input), 'x')
number_of_registers = len(registers_info)
registers_polynomial = [0 for _ in range(number_of_registers)]
registers_start = [0 for _ in range(number_of_registers)]
registers_update_bit = [0 for _ in range(number_of_registers)]
clock_polynomials = [None for _ in range(number_of_registers)]
end = 0

for i in range(number_of_registers):
registers_start[i] = end
end += registers_info[i][0]
registers_update_bit[i] = end - 1
registers_polynomial[i] = get_polynomail(registers_info[i][1], R)
if len(registers_info[i]) > 2:
clock_polynomials[i] = get_polynomail(registers_info[i][2], R)

for r in range(number_of_clocks):
do_clocks = [True for _ in range(number_of_registers)]
output_bits = [0 for _ in range(number_of_registers)]
for j in range(number_of_registers):
if clock_polynomials[j] is not None:
do_clocks[j] = int(clock_polynomials[j](*output))
if do_clocks[j] > 0:
output_bits[j] = int(registers_polynomial[j](*output))

for j in range(number_of_registers):
if do_clocks[j] > 0:
output.rol(1, registers_start[j], registers_update_bit[j] + 1)
output[registers_update_bit[j]] = output_bits[j]
if verbosity:
print("FSR:")
for i in range(number_of_registers):
print(" F = {}".format(registers_polynomial[i]))
if clock_polynomials[i] is None:
print("register_" + str(i + 1) + " clocks:", True)
else:
print("register_" + str(i + 1) + " poly = {}".format(clock_polynomials[i]))
print("number of clocks: ", number_of_clocks)
print(input_expression.format(input.bin))
print(output_expression.format(output.bin))
return output


def fsr_word(input, registers_info, bits_inside_word, number_of_clocks, verbosity=False):
"""
INPUT:

- ``input`` -- **BitArray object**; a BitArray
- ``registers_info`` -- **list**; a list of [register_bit_length, register_polynomial, clock_polynomial (optional)],
register_bit_length is an integer to indicates the length of register. register_polynomial and clock_polynomial
are lists of monomials, which is presented in the integer list. For example [[0], [1], [2, 3]] represents
x0+x1+x2*x3. [] represents 1.
- ``number_of_clocks`` -- **integer**; indicates how many bits in a word this fsr component would operate. By
default, it is 1.
- ``number_of_clocks`` -- **integer**; indicates how many loops this fsr component would operate.
- ``verbosity`` -- **boolean** (default: `False`); set this flag to True to print the input/output
"""

def bits_to_word(input, bits_inside_word, word_gf):
y = word_gf.gen()

monomials = [pow(y, i) for i in range(bits_inside_word - 1, -1, -1)]
word_array = [0 for _ in
range(int(len(input) / bits_inside_word))]

for i in range(len(word_array)):
c = 0
for j in range(len(monomials)):
c += (input[(i * 8) + j]) * monomials[j]
word_array[i] = c

return word_array

def word_to_bits(word_array, bits_inside_word):
output = BitArray()
s = f'0b'
for _ in word_array[0]:
kl = list(_)
for j in range(bits_inside_word - 1, -1, -1):
v = f'1' if kl[j] else f'0'
s = s + v
output.append(s)
return output

def get_polynomail(polynomial_index_list, R):
if polynomial_index_list == []:
return R(1)
p = 0
x = R.gens()
y = R.construction()[1].gen()

for _ in polynomial_index_list:
m = 0 # presently it is for field of characteristic 2 only
cc = "{0:b}".format(_[0])
for i in range(len(cc)):
if cc[i] == '1': m = m + pow(y, len(cc) - 1 - i)
for i in _[1]:
m = m * x[i]
p += m
return p

word_gf = GF(pow(2, bits_inside_word))
word_array = bits_to_word(input, bits_inside_word, word_gf)
R = PolynomialRing(word_gf, len(word_array), 'x')
number_of_registers = len(registers_info)
registers_polynomial = [0 for _ in range(number_of_registers)]
registers_start = [0 for _ in range(number_of_registers)]
registers_update_word = [0 for _ in range(number_of_registers)]
clock_polynomials = [None for _ in range(number_of_registers)]
end = 0
for i in range(number_of_registers):
registers_start[i] = end
end += registers_info[i][0]
registers_update_word[i] = end - 1
registers_polynomial[i] = get_polynomail(registers_info[i][1], R)
if len(registers_info[i]) > 2:
clock_polynomials[i] = get_polynomail(registers_info[i][2], R)
for r in range(number_of_clocks):
do_clocks = [True for _ in range(number_of_registers)]
output_words = [0 for _ in range(number_of_registers)]
for j in range(number_of_registers):
if clock_polynomials[j] is not None:
do_clocks[j] = clock_polynomials[j](*word_array)
if do_clocks[j] > 0:
output_words[j] = registers_polynomial[j](*word_array)

registers = []
for j in range(number_of_registers):
reg = word_array[registers_start[j]:registers_update_word[j] + 1]
if do_clocks[j] > 0:
reg = reg[1:]
reg.append(output_words[j])
registers.append(reg)
word_array = registers

output = word_to_bits(word_array, bits_inside_word)
if verbosity:
print("FSR:")
for i in range(number_of_registers):
print(" F = {}".format(registers_polynomial[i]))
for i in range(number_of_registers):
if clock_polynomials[i] is None:
print("register_" + str(i + 1) + " clocks:", True)
else:
print("register_" + str(i + 1) + " poly = {}".format(clock_polynomials[i]))
print("number of clocks: ", number_of_clocks)
print(input_expression.format(input.bin))
print(output_expression.format(output.bin))
return output
1 change: 1 addition & 0 deletions claasp/cipher_modules/generic_functions_vectorized_bit.py
Original file line number Diff line number Diff line change
Expand Up @@ -501,3 +501,4 @@ def bit_vector_mix_column_poly0(input, matrix, verbosity=False):
print("---")

return output

1 change: 1 addition & 0 deletions claasp/cipher_modules/generic_functions_vectorized_byte.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import numpy as np
from copy import copy
from functools import reduce
from operator import xor

NB = 8 # Number of bits of the representation

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
from claasp.DTOs.component_state import ComponentState

SBOX_CELL_SIZE = 8
CONSTANT_ZERO_LEN = 7
PARAMETERS_CONFIGURATION_LIST = [{'state_bit_size': 160, 'number_of_rounds': 80},
{'state_bit_size': 176, 'number_of_rounds': 90}]
S_BOX = [0xee, 0xed, 0xeb, 0xe0, 0xe2, 0xe1, 0xe4, 0xef, 0xe7, 0xea, 0xe8, 0xe5, 0xe9, 0xec, 0xe3, 0xe6,
Expand Down
Loading