Skip to content

Commit

Permalink
Merge pull request #211 from Crypto-TII/develop
Browse files Browse the repository at this point in the history
  • Loading branch information
peacker authored Apr 6, 2024
2 parents 94f6cf4 + 03ebbc5 commit b9d886a
Show file tree
Hide file tree
Showing 32 changed files with 784 additions and 480 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/run-benchmark-tests.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Run benchmark tests
name: run-benchmark-tests
on:
pull_request_target:
pull_request:
types: [ opened, synchronize, reopened, edited ]
branches:
- main
Expand Down
7 changes: 3 additions & 4 deletions .github/workflows/run-pytest-and-sonarcloud-scan.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
push:
branches:
- '**'
pull_request_target:
pull_request:
types: [opened, synchronize, reopened, edited]
branches:
- develop
Expand Down Expand Up @@ -47,11 +47,10 @@ jobs:
path: /home/runner/_work/claasp/coverage.xml

run-code-coverage:
if: ${{ !github.event.repository.fork }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v2
with:
persist-credentials: false
fetch-depth: 0
Expand All @@ -73,4 +72,4 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
needs: run-pytest
needs: run-pytest
6 changes: 3 additions & 3 deletions .github/workflows/update-changelog.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
uses: actions-js/push@master
if: ${{ env.should_add_last_changes_to_master == 'true' }}
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
github_token: ${{ secrets.AUTHORIZATION_TOKEN }}
message: 'Changelog version updated'
tags: true
force: true
Expand All @@ -49,7 +49,7 @@ jobs:
if: ${{ env.should_add_last_changes_to_master == 'true' }}
uses: rickstaa/action-create-tag@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
github_token: ${{ secrets.AUTHORIZATION_TOKEN }}
tag: ${{ env.tag_name }}
tag_exists_error: false
message: ${{ env.release_message }}
Expand Down Expand Up @@ -80,5 +80,5 @@ jobs:
with:
target: 'develop'
source: 'main'
token: ${{ secrets.GITHUB_TOKEN }}
token: ${{ secrets.AUTHORIZATION_TOKEN }}
strategy_options: 'ours'
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v2.1.0
v2.3.0
29 changes: 15 additions & 14 deletions claasp/cipher_modules/algebraic_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,49 +31,50 @@ 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]}}
"""

def __init__(self, cipher):
self._cipher = cipher
self._algebraic_model = AlgebraicModel(cipher)

def algebraic_tests(self, timeout_in_seconds=60):
from sage.structure.sequence import Sequence
nvars_up_to_round = []

npolynomials_up_to_round = []
nmonomials_up_to_round = []
max_deg_of_equations_up_to_round = []
tests_up_to_round = []

F = []

algebraic_model = AlgebraicModel(self._cipher)
constant_vars = {}
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 += 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)
Fseq = Sequence(F)
nvars_up_to_round.append(Fseq.nvariables())
npolynomials_up_to_round.append(len(Fseq))
Expand Down
133 changes: 105 additions & 28 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 @@ -78,25 +77,11 @@ def connection_polynomials_at_round(self, r):
plaintext_y23 + sbox_0_5_x3]
"""
polynomials = []
R = self.ring()

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))

input_vars, prev_input_vars = self._input_vars_previous_input_vars(component)
polynomials += [x + y for (x, y) in zip(input_vars, prev_input_vars)]

return polynomials
Expand All @@ -107,15 +92,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,18 +149,48 @@ 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 228 Polynomials in 144 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 288 Polynomials in 352 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 198 Polynomials in 128 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 352 Polynomials in 448 Variables
"""
polynomials = sum([self.polynomial_system_at_round(r) for r in range(self._cipher.number_of_rounds)], [])
polynomials += self.connection_polynomials()
polynomials = []
constant_vars = {}
for r in range(self._cipher.number_of_rounds):
polynomials += self.polynomial_system_at_round(r, True)
constant_vars.update(self._dict_constant_component_polynomials(r))
if constant_vars is not None:
polynomials = self._remove_constant_polynomials(constant_vars, polynomials)

return Sequence(polynomials)

def polynomial_system_at_round(self, r):
def polynomial_system_at_round(self, r, fun_call_flag=False):
"""
Return a polynomial system at round `r`.
Expand All @@ -188,8 +203,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 228 Polynomials in 144 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 +224,70 @@ 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)

if fun_call_flag is False:
constant_vars = self._dict_constant_component_polynomials(r)
if constant_vars is not None:
polynomials = self._remove_constant_polynomials(constant_vars, polynomials)

return Sequence(polynomials)

def _apply_connection_variable_mapping(self, polys, r):

if not polys:
return polys

variable_substitution_dict = {}

for component in self._cipher.get_components_in_round(r):
if component.type == "constant":
continue
input_vars, prev_input_vars = self._input_vars_previous_input_vars(component)
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 _input_vars_previous_input_vars(self, component):
input_vars = [component.id + "_" + self.input_postfix + str(i) for i in range(component.input_bit_size)]
input_vars = list(map(self.ring(), 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(self.ring(), prev_input_vars))
return input_vars, prev_input_vars

def _dict_constant_component_polynomials(self, round_number):

constant_vars = {}
for component in self._cipher.get_components_in_round(round_number):
if component.type == "constant":
output_vars = [component.id + "_" + self.output_postfix + str(i) for i in
range(component.output_bit_size)]
else:
continue
output_vars = list(map(self.ring(), output_vars))
constant = int(component.description[0], 16)
b = list(map(int, reversed(bin(constant)[2:])))
b += [0] * (component.output_bit_size - len(b))
constant_vars.update({x: y for x, y in zip(output_vars, b)})
return constant_vars

def _remove_constant_polynomials(self, constant_vars, polys):

polys = Sequence(polys).subs(constant_vars)
polys = [p for p in polys if p != 0]
return polys

def ring(self):
"""
Return the polynomial ring for the system of equations.
Expand Down
Loading

0 comments on commit b9d886a

Please sign in to comment.