Skip to content

Commit

Permalink
Merge pull request #120 from Crypto-TII/feature/add_minors_algorithm_…
Browse files Browse the repository at this point in the history
…mr_estimator

Feat:minors algorithm for the MREstimator
  • Loading branch information
Javierverbel authored Jan 22, 2024
2 parents 86bd12c + 5794a6d commit c96c2bd
Show file tree
Hide file tree
Showing 4 changed files with 241 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .support_minors import SupportMinors
from .kernel_search import KernelSearch
from .big_k import BigK
from .minors import Minors
165 changes: 165 additions & 0 deletions cryptographic_estimators/MREstimator/MRAlgorithms/minors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
# ****************************************************************************
# Copyright 2023 Technology Innovation Institute
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# ****************************************************************************

from ...MREstimator.mr_algorithm import MRAlgorithm
from ...MREstimator.mr_problem import MRProblem
from ...base_algorithm import optimal_parameter
from math import log2, ceil
from math import comb as binomial
from .mr_helper import minors_polynomial
from ..mr_constants import MR_NUMBER_OF_KERNEL_VECTORS_TO_GUESS, MR_NUMBER_OF_COEFFICIENTS_TO_GUESS


class Minors(MRAlgorithm):
"""
Construct an instance of Minors estimator
INPUT:
- ``problem`` -- an instance of the MRProblem class
- ``w`` -- linear algebra constant (default: 3)
- ``theta`` -- exponent of the conversion factor (default: 2.81)
EXAMPLES::
sage: from cryptographic_estimators.MREstimator.MRAlgorithms.minors import Minors
sage: from cryptographic_estimators.MREstimator.mr_problem import MRProblem
sage: E = Minors(MRProblem(q=7, m=9, n=10, k=15, r=4))
sage: E
Minors estimator for the MinRank problem with (q, m, n, k, r) = (7, 9, 10, 15, 4)
"""

def __init__(self, problem: MRProblem, **kwargs):

super(Minors, self).__init__(problem, **kwargs)

q, m, n, k, r = self.problem.get_parameters()
self.set_parameter_ranges('a', 0, min(n - r, ceil(k / m)))
self.set_parameter_ranges('lv', 0, r)
self._name = "Minors"

@optimal_parameter
def a(self):
"""
Return the optimal `a`, i.e. no. of vectors to guess in the kernel of the low-rank matrix
EXAMPLES::
sage: from cryptographic_estimators.MREstimator.MRAlgorithms.minors import Minors
sage: from cryptographic_estimators.MREstimator.mr_problem import MRProblem
sage: ME = Minors(MRProblem(q=7, m=9, n=10, k=15, r=4))
sage: ME.a()
2
TESTS::
sage: from cryptographic_estimators.MREstimator.MRAlgorithms.minors import Minors
sage: from cryptographic_estimators.MREstimator.mr_problem import MRProblem
sage: ME = Minors(MRProblem(q=16, m=15, n=15, k=78, r=6))
sage: ME.a()
5
"""
return self._get_optimal_parameter(MR_NUMBER_OF_KERNEL_VECTORS_TO_GUESS)

@optimal_parameter
def lv(self):
"""
Return the optimal `lv`, i.e. no. of entries to guess in the solution
EXAMPLES::
sage: from cryptographic_estimators.MREstimator.MRAlgorithms.minors import Minors
sage: from cryptographic_estimators.MREstimator.mr_problem import MRProblem
sage: ME = Minors(MRProblem(q=7, m=9, n=10, k=15, r=4))
sage: ME.lv()
0
TESTS::
sage: from cryptographic_estimators.MREstimator.MRAlgorithms.minors import Minors
sage: from cryptographic_estimators.MREstimator.mr_problem import MRProblem
sage: ME = Minors(MRProblem(q=16, m=15, n=15, k=78, r=6))
sage: ME.lv()
0
"""
return self._get_optimal_parameter(MR_NUMBER_OF_COEFFICIENTS_TO_GUESS)

def _ME_time_memory_complexity_helper_(self, m: int, n_reduced: int, k_reduced: int, r: int, time_mem: str):
out = 0
poly = minors_polynomial(m, n_reduced, k_reduced, r)
D = poly.degree()
if k_reduced > 0:
if time_mem == "time":
w = self._w
out = w * log2(binomial(k_reduced + D, D))
elif time_mem == "memory":
out = 2 * log2(binomial(k_reduced + D, D))
return out


def _compute_time_complexity(self, parameters: dict):
"""
Return the time complexity of the algorithm for a given set of parameters
INPUT:
- ``parameters`` -- dictionary including the parameters
TESTS::
sage: from cryptographic_estimators.MREstimator.MRAlgorithms.minors import Minors
sage: from cryptographic_estimators.MREstimator.mr_problem import MRProblem
sage: ME = Minors(MRProblem(q=16, m=15, n=15, k=78, r=6))
sage: ME.time_complexity()
143.1769522683363
"""
a = parameters[MR_NUMBER_OF_KERNEL_VECTORS_TO_GUESS]
lv = parameters[MR_NUMBER_OF_COEFFICIENTS_TO_GUESS]
q, m, _, k, r = self.problem.get_parameters()
_, _, n_reduced, k_reduced, _ = self.get_problem_parameters_reduced(a, lv)
time = self.hybridization_factor(a, lv)
time_complexity = self._ME_time_memory_complexity_helper_(m, n_reduced, k_reduced, r, "time")
reduction_cost = self.cost_reduction(a)
time += max(time_complexity, reduction_cost)
if abs(time_complexity - reduction_cost) < 0:
time += 1
return time

def _compute_memory_complexity(self, parameters: dict):
"""
Return the memory complexity of the algorithm for a given set of parameters
INPUT:
- ``parameters`` -- dictionary including the parameters
TESTS::
sage: from cryptographic_estimators.MREstimator.MRAlgorithms.minors import Minors
sage: from cryptographic_estimators.MREstimator.mr_problem import MRProblem
sage: ME = Minors(MRProblem(q=16, m=15, n=15, k=78, r=6))
sage: ME.memory_complexity()
14.784634845557521
"""

a = parameters[MR_NUMBER_OF_KERNEL_VECTORS_TO_GUESS]
lv = parameters[MR_NUMBER_OF_COEFFICIENTS_TO_GUESS]
q, m, n, k, r = self.problem.get_parameters()
_, _, n_reduced, k_reduced, _ = self.get_problem_parameters_reduced(a, lv)
memory = self._ME_time_memory_complexity_helper_(m, n_reduced, k_reduced, r, "memory")
return memory
62 changes: 62 additions & 0 deletions cryptographic_estimators/MREstimator/MRAlgorithms/mr_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# ****************************************************************************
# Copyright 2023 Technology Innovation Institute
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# ****************************************************************************


from sage.all import QQ
from sage.rings.power_series_ring import PowerSeriesRing
from itertools import product
from math import comb as binomial
from sage.matrix.special import zero_matrix
from math import log2

def _binomial_mult(n, m, i, j, l):
return binomial(m - i, l) * binomial(n - j, l)

def entry_i_j_of_A(n, m, t, i, j):
limit = max(m - i, n - j)
return sum([_binomial_mult(n, m, i, j, l) * t ** l for l in range(limit + 1)])

def matrix_A(m, n, r, PR):
A = zero_matrix(PR, r, r)
t = PR.gen()
square_r = range(1, r + 1)
for i, j in product(square_r, square_r):
entry_i_j = entry_i_j_of_A(n, m, t, i, j)
A.add_to_entry(i-1, j-1, entry_i_j)
return A

def deteterminant_of_A(m, n, r, t):
A = matrix_A(m, n, r, t)
return A.determinant()

def minors_series(m, n, k, r):
PR = PowerSeriesRing(QQ, 't', default_prec=max(n, m) + 2)
t = PR.gen()
exp = (m - r) * (n - r) - (k + 1)
series = (1 - t) ** exp * deteterminant_of_A(m, n, r, PR)/(t ** binomial(r, 2))
return series

def minors_polynomial(m, n_reduced, k_reduced, r):
poly = 0
series = minors_series(m, n_reduced, k_reduced, r)
t = series.parent().gen()
for D in range(series.degree()):
poly += series[D] * t ** D
if series[D + 1] <= 0:
break
return poly

13 changes: 13 additions & 0 deletions cryptographic_estimators/MREstimator/mr_estimator.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ def table(self, show_quantum_complexity=0, show_tilde_o_time=0,
| SupportMinors | 38.8 | 13.0 | {'a': 1, 'lv': 0, 'b': 1, 'nprime': 8, 'variant': 'block_wiedemann'} |
| KernelSearch | 33.2 | 11.5 | {'a': 1, 'lv': 0} |
| BigK | 132.5 | 13.1 | {'a': 0, 'lv': 0} |
| Minors | 37.2 | 1.6 | {'a': 2, 'lv': 0} |
+---------------+-------+--------+----------------------------------------------------------------------+
TESTS:
Expand All @@ -91,8 +92,10 @@ def table(self, show_quantum_complexity=0, show_tilde_o_time=0,
| SupportMinors | 144.0 | 11.8 | {'a': 5, 'lv': 0, 'b': 1, 'nprime': 8, 'variant': 'block_wiedemann'} |
| KernelSearch | 147.7 | 14.3 | {'a': 4, 'lv': 3} |
| BigK | 154.7 | 13.8 | {'a': 5, 'lv': 3} |
| Minors | 143.2 | 14.8 | {'a': 5, 'lv': 0} |
+---------------+-------+--------+----------------------------------------------------------------------+
sage: MRE = MREstimator(q=16, m=16, n=16, k=142, r=4)
sage: MRE.table(show_all_parameters=1)
+---------------+---------------------------------------------------------------------------------------+
Expand All @@ -103,8 +106,10 @@ def table(self, show_quantum_complexity=0, show_tilde_o_time=0,
| SupportMinors | 165.9 | 18.0 | {'a': 8, 'lv': 0, 'b': 2, 'nprime': 8, 'variant': 'block_wiedemann'} |
| KernelSearch | 159.4 | 13.8 | {'a': 8, 'lv': 0} |
| BigK | 230.8 | 17.2 | {'a': 0, 'lv': 0} |
| Minors | 162.5 | 33.0 | {'a': 7, 'lv': 0} |
+---------------+-------+--------+----------------------------------------------------------------------+
sage: MRE = MREstimator(q=16, m=19, n=19, k=109, r=8)
sage: MRE.table(show_all_parameters=1)
+---------------+----------------------------------------------------------------------------------------+
Expand All @@ -115,8 +120,10 @@ def table(self, show_quantum_complexity=0, show_tilde_o_time=0,
| SupportMinors | 209.6 | 23.5 | {'a': 5, 'lv': 0, 'b': 2, 'nprime': 14, 'variant': 'block_wiedemann'} |
| KernelSearch | 207.4 | 14.9 | {'a': 5, 'lv': 0} |
| BigK | 431.1 | 17.4 | {'a': 0, 'lv': 0} |
| Minors | 211.5 | 55.0 | {'a': 4, 'lv': 0} |
+---------------+-------+--------+-----------------------------------------------------------------------+
sage: MRE = MREstimator(q=16, m=19, n=19, k=167, r=6)
sage: MRE.table(show_all_parameters=1)
+---------------+----------------------------------------------------------------------------------------+
Expand All @@ -127,8 +134,10 @@ def table(self, show_quantum_complexity=0, show_tilde_o_time=0,
| SupportMinors | 236.3 | 20.9 | {'a': 8, 'lv': 0, 'b': 2, 'nprime': 11, 'variant': 'block_wiedemann'} |
| KernelSearch | 231.7 | 14.6 | {'a': 8, 'lv': 0} |
| BigK | 351.8 | 17.9 | {'a': 0, 'lv': 0} |
| Minors | 237.6 | 45.7 | {'a': 7, 'lv': 0} |
+---------------+-------+--------+-----------------------------------------------------------------------+
sage: MRE = MREstimator(q=16, m=21, n=21, k=189, r=7)
sage: MRE.table(show_all_parameters=1)
+---------------+----------------------------------------------------------------------------------------+
Expand All @@ -139,8 +148,10 @@ def table(self, show_quantum_complexity=0, show_tilde_o_time=0,
| SupportMinors | 274.5 | 51.0 | {'a': 6, 'lv': 0, 'b': 8, 'nprime': 15, 'variant': 'block_wiedemann'} |
| KernelSearch | 269.2 | 15.5 | {'a': 8, 'lv': 0} |
| BigK | 452.6 | 18.4 | {'a': 0, 'lv': 0} |
| Minors | 278.7 | 2.0 | {'a': 9, 'lv': 0} |
+---------------+-------+--------+-----------------------------------------------------------------------+
sage: MRE = MREstimator(q=16, m=22, n=22, k=254, r=6)
sage: MRE.table(show_all_parameters=1)
+---------------+-----------------------------------------------------------------------------------------+
Expand All @@ -151,8 +162,10 @@ def table(self, show_quantum_complexity=0, show_tilde_o_time=0,
| SupportMinors | 301.2 | 17.6 | {'a': 11, 'lv': 0, 'b': 1, 'nprime': 11, 'variant': 'block_wiedemann'} |
| KernelSearch | 302.8 | 14.5 | {'a': 11, 'lv': 0} |
| BigK | 425.4 | 18.9 | {'a': 0, 'lv': 0} |
| Minors | 307.1 | 60.1 | {'a': 9, 'lv': 0} |
+---------------+-------+--------+------------------------------------------------------------------------+
"""
super(MREstimator, self).table(show_quantum_complexity=show_quantum_complexity,
show_tilde_o_time=show_tilde_o_time,
Expand Down

0 comments on commit c96c2bd

Please sign in to comment.