Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/remove connection polynomials and connection variables #206

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
21 changes: 10 additions & 11 deletions claasp/cipher_modules/algebraic_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,26 @@ class AlgebraicTests:
sage: toyspn = ToySPN1(number_of_rounds=2)
sage: alg_test = AlgebraicTests(toyspn)
sage: alg_test.algebraic_tests(timeout_in_seconds=10)
{'input_parameters': {'cipher.id': 'toyspn1_p6_k6_o6_r2',
{'input_parameters': {'cipher': toyspn1_p6_k6_o6_r2,
'timeout_in_seconds': 10,
'test_name': 'algebraic_tests'},
'test_results': {'number_of_variables': [66, 126],
'number_of_equations': [76, 158],
'number_of_monomials': [96, 186],
'test_results': {'number_of_variables': [30, 48],
'number_of_equations': [40, 80],
'number_of_monomials': [60, 108],
'max_degree_of_equations': [2, 2],
'test_passed': [False, True]}}
'test_passed': [False, False]}}

sage: from claasp.cipher_modules.algebraic_tests import AlgebraicTests
sage: from claasp.ciphers.block_ciphers.speck_block_cipher import SpeckBlockCipher
sage: speck = SpeckBlockCipher(number_of_rounds=1)
sage: alg_test = AlgebraicTests(speck)
sage: alg_test.algebraic_tests(timeout_in_seconds=30)
{'input_parameters': {'cipher.id': 'speck_p32_k64_o32_r1',
{'input_parameters': {'cipher': speck_p32_k64_o32_r1,
'timeout_in_seconds': 30,
'test_name': 'algebraic_tests'},
'test_results': {'number_of_variables': [320],
'number_of_equations': [272],
'number_of_monomials': [365],
'test_results': {'number_of_variables': [144],
'number_of_equations': [96],
'number_of_monomials': [189],
'max_degree_of_equations': [2],
'test_passed': [True]}}

Expand All @@ -72,8 +72,7 @@ def algebraic_tests(self, timeout_in_seconds=60):

algebraic_model = AlgebraicModel(self._cipher)
for round_number in range(self._cipher.number_of_rounds):
F += algebraic_model.polynomial_system_at_round(round_number) + \
algebraic_model.connection_polynomials_at_round(round_number)
F += algebraic_model.polynomial_system_at_round(round_number)
Fseq = Sequence(F)
nvars_up_to_round.append(Fseq.nvariables())
npolynomials_up_to_round.append(len(Fseq))
Expand Down
80 changes: 68 additions & 12 deletions claasp/cipher_modules/models/algebraic/algebraic_model.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

# ****************************************************************************
# Copyright 2023 Technology Innovation Institute
#
Expand Down Expand Up @@ -107,15 +106,15 @@ def is_algebraically_secure(self, timeout):

INPUT:

- ``timeout`` -- **integer**; the timeout for the Grobner basis computation in seconds
- ``timeout`` -- **integer**; the timeout for the Groebner basis computation in seconds

EXAMPLES::

sage: from claasp.cipher_modules.models.algebraic.algebraic_model import AlgebraicModel
sage: from claasp.ciphers.block_ciphers.identity_block_cipher import IdentityBlockCipher
sage: identity = IdentityBlockCipher()
sage: algebraic = AlgebraicModel(identity)
sage: algebraic.is_algebraically_secure(120)
sage: from claasp.ciphers.toys.toyspn1 import ToySPN1
sage: toyspn = ToySPN1()
sage: algebraic = AlgebraicModel(toyspn)
sage: algebraic.is_algebraically_secure(30)
False
"""
from cysignals.alarm import alarm, cancel_alarm
Expand Down Expand Up @@ -164,14 +163,40 @@ def polynomial_system(self):

EXAMPLES::

sage: from claasp.ciphers.toys.toyspn1 import ToySPN1
sage: from claasp.cipher_modules.models.algebraic.algebraic_model import AlgebraicModel
sage: toyspn = ToySPN1()
sage: AlgebraicModel(toyspn).polynomial_system()
Polynomial Sequence with 80 Polynomials in 48 Variables

sage: from claasp.ciphers.block_ciphers.fancy_block_cipher import FancyBlockCipher
sage: from claasp.cipher_modules.models.algebraic.algebraic_model import AlgebraicModel
sage: fancy = FancyBlockCipher(number_of_rounds=1)
sage: AlgebraicModel(fancy).polynomial_system() # long time
Polynomial Sequence with 468 Polynomials in 384 Variables
sage: AlgebraicModel(fancy).polynomial_system()
Polynomial Sequence with 252 Polynomials in 168 Variables

sage: from claasp.ciphers.block_ciphers.speck_block_cipher import SpeckBlockCipher
sage: from claasp.cipher_modules.models.algebraic.algebraic_model import AlgebraicModel
sage: speck = SpeckBlockCipher(number_of_rounds=2)
sage: AlgebraicModel(speck).polynomial_system()
Polynomial Sequence with 304 Polynomials in 368 Variables

sage: from claasp.ciphers.block_ciphers.aes_block_cipher import AESBlockCipher
sage: from claasp.cipher_modules.models.algebraic.algebraic_model import AlgebraicModel
sage: aes = AESBlockCipher(word_size=4, state_size=2, number_of_rounds=1)
sage: AlgebraicModel(aes).polynomial_system()
Polynomial Sequence with 206 Polynomials in 136 Variables

sage: from claasp.ciphers.block_ciphers.tea_block_cipher import TeaBlockCipher
sage: from claasp.cipher_modules.models.algebraic.algebraic_model import AlgebraicModel
sage: tea = TeaBlockCipher(block_bit_size=32, key_bit_size=64, number_of_rounds=1)
sage: AlgebraicModel(tea).polynomial_system()
Polynomial Sequence with 368 Polynomials in 464 Variables

"""
polynomials = sum([self.polynomial_system_at_round(r) for r in range(self._cipher.number_of_rounds)], [])
polynomials += self.connection_polynomials()
polynomials = []
for r in range(self._cipher.number_of_rounds):
polynomials += self.polynomial_system_at_round(r)

return Sequence(polynomials)

Expand All @@ -188,8 +213,8 @@ def polynomial_system_at_round(self, r):
sage: from claasp.ciphers.block_ciphers.fancy_block_cipher import FancyBlockCipher
sage: from claasp.cipher_modules.models.algebraic.algebraic_model import AlgebraicModel
sage: fancy = FancyBlockCipher(number_of_rounds=1)
sage: AlgebraicModel(fancy).polynomial_system_at_round(0) # long time
Polynomial Sequence with 252 Polynomials in 288 Variables
sage: AlgebraicModel(fancy).polynomial_system_at_round(0)
Polynomial Sequence with 252 Polynomials in 168 Variables
"""
if not 0 <= r < self._cipher.number_of_rounds:
raise ValueError(f"r must be in the range 0 <= r < {self._cipher.number_of_rounds}")
Expand All @@ -209,8 +234,39 @@ def polynomial_system_at_round(self, r):
operation in ['ROTATE_BY_VARIABLE_AMOUNT', 'SHIFT_BY_VARIABLE_AMOUNT']:
raise ValueError(f"polynomial generation of {operation} operation is not supported at present")

polynomials = self._apply_connection_variable_mapping(Sequence(polynomials), r)
return Sequence(polynomials)

def _apply_connection_variable_mapping(self, polys, r):

if not polys:
return polys

R = self.ring()
variable_substitution_dict = {}

for component in self._cipher.get_components_in_round(r):
if component.type == "constant":
continue
input_vars = [component.id + "_" + self.input_postfix + str(i) for i in range(component.input_bit_size)]
input_vars = list(map(R, input_vars))
input_links = component.input_id_links
input_positions = component.input_bit_positions

prev_input_vars = []
for k in range(len(input_links)):
prev_input_vars += [input_links[k] + "_" + self.output_postfix + str(i) for i in
input_positions[k]]
prev_input_vars = list(map(R, prev_input_vars))
if component.type != "cipher_output":
variable_substitution_dict.update({x: y for x, y in zip(input_vars, prev_input_vars)})
else:
variable_substitution_dict.update({y: x for x, y in zip(input_vars, prev_input_vars)})

polys = polys.subs(variable_substitution_dict)

return polys

def ring(self):
"""
Return the polynomial ring for the system of equations.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ def test_nvars():
def test_polynomial_system():
fancy = FancyBlockCipher(number_of_rounds=1)
assert str(AlgebraicModel(fancy).polynomial_system()) == \
'Polynomial Sequence with 468 Polynomials in 384 Variables'
'Polynomial Sequence with 252 Polynomials in 168 Variables'


def test_polynomial_system_at_round():
fancy = FancyBlockCipher(number_of_rounds=1)
assert str(AlgebraicModel(fancy).polynomial_system_at_round(0)) == \
'Polynomial Sequence with 252 Polynomials in 288 Variables'
'Polynomial Sequence with 252 Polynomials in 168 Variables'


def test_ring():
Expand Down
16 changes: 8 additions & 8 deletions tests/unit/cipher_modules/report_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ def test_save_as_latex_table():
trail_report = Report(trail)
trail_report.save_as_latex_table()

nist = NISTStatisticalTests(simon)
report_sts = Report(nist.nist_statistical_tests('avalanche'))
dieharder=DieharderTests(simon)
report_sts = Report(dieharder.dieharder_statistical_tests('avalanche', dieharder_test_option=100))
report_sts.save_as_latex_table()

def test_save_as_DataFrame():
Expand All @@ -100,8 +100,8 @@ def test_save_as_DataFrame():
trail_report = Report(trail)
trail_report.save_as_DataFrame()

nist = NISTStatisticalTests(speck)
report_sts = Report(nist.nist_statistical_tests('avalanche'))
dieharder = DieharderTests(speck)
report_sts = Report(dieharder.dieharder_statistical_tests('avalanche', dieharder_test_option=100))
report_sts.save_as_DataFrame()


Expand All @@ -112,8 +112,8 @@ def test_save_as_json():
simon).neural_network_blackbox_distinguisher_tests()
blackbox_report = Report(neural_network_blackbox_distinguisher_tests_results)
blackbox_report.save_as_json(fixed_input='plaintext',fixed_output='round_output')
nist = NISTStatisticalTests(simon)
report_sts = Report(nist.nist_statistical_tests('avalanche'))
dieharder = DieharderTests(simon)
report_sts = Report(dieharder.dieharder_statistical_tests('avalanche', dieharder_test_option=100))
report_sts.save_as_json()
milp = MilpXorDifferentialModel(simon)
plaintext = set_fixed_variables(
Expand Down Expand Up @@ -173,8 +173,8 @@ def test_show():
trail_report = Report(trail)
trail_report.show()

nist = NISTStatisticalTests(speck)
report_sts = Report(nist.nist_statistical_tests('avalanche'))
dieharder = DieharderTests(speck)
report_sts = Report(dieharder.dieharder_statistical_tests('avalanche', dieharder_test_option=100))
report_sts.show()

neural_network_tests = NeuralNetworkTests(speck).neural_network_differential_distinguisher_tests()
Expand Down
41 changes: 21 additions & 20 deletions tests/unit/cipher_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,33 +53,33 @@ def test_algebraic_tests():
d = AlgebraicTests(toyspn).algebraic_tests(10)
assert d == {
'input_parameters': {'cipher': toyspn, 'timeout_in_seconds': 10, 'test_name': 'algebraic_tests'},
'test_results': {'number_of_variables': [66, 126],
'number_of_equations': [76, 158],
'number_of_monomials': [96, 186],
'test_results': {'number_of_variables': [30, 48],
'number_of_equations': [40, 80],
'number_of_monomials': [60, 108],
'max_degree_of_equations': [2, 2],
'test_passed': [False, True]}}
'test_passed': [False, False]}}

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_in_seconds': 1,
'test_name': 'algebraic_tests'},
'test_results': {'number_of_variables': [320],
'number_of_equations': [272],
'number_of_monomials': [365],
'timeout_in_seconds': 1,
'test_name': 'algebraic_tests'},
'test_results': {'number_of_variables': [144],
'number_of_equations': [96],
'number_of_monomials': [189],
'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': aes,
'timeout_in_seconds': 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]}}
'timeout_in_seconds': 5,
'test_name': 'algebraic_tests'},
'test_results': {'number_of_variables': [136],
'number_of_equations': [206],
'number_of_monomials': [304],
'max_degree_of_equations': [2],
'test_passed': [False]}}

assert d == compare_result

Expand Down Expand Up @@ -202,8 +202,8 @@ def test_impossible_differential_search():


def test_is_algebraically_secure():
identity = IdentityBlockCipher()
assert identity.is_algebraically_secure(120) is False
aes = AESBlockCipher(word_size=4, state_size=2, number_of_rounds = 1)
assert aes.is_algebraically_secure(20) is False


def test_is_andrx():
Expand Down Expand Up @@ -233,12 +233,13 @@ def test_is_spn():


def test_polynomial_system():
assert str(IdentityBlockCipher().polynomial_system()) == 'Polynomial Sequence with 128 Polynomials in 256 Variables'
tea = TeaBlockCipher(block_bit_size=32, key_bit_size=64, number_of_rounds=1)
assert str(tea.polynomial_system()) == 'Polynomial Sequence with 368 Polynomials in 464 Variables'


def test_polynomial_system_at_round():
assert str(FancyBlockCipher(number_of_rounds=1).polynomial_system_at_round(0)) == \
'Polynomial Sequence with 252 Polynomials in 288 Variables'
'Polynomial Sequence with 252 Polynomials in 168 Variables'


def test_print():
Expand Down
Loading