From 19a43acaed4a9ded7ae0f044ad289e56de03005a Mon Sep 17 00:00:00 2001 From: "Martin R. Albrecht" Date: Wed, 7 Feb 2024 14:35:53 +0000 Subject: [PATCH 01/10] whitespace --- estimator/sis_lattice.py | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/estimator/sis_lattice.py b/estimator/sis_lattice.py index 6063e9a..9109839 100644 --- a/estimator/sis_lattice.py +++ b/estimator/sis_lattice.py @@ -26,12 +26,13 @@ class SISLattice: """ Estimate cost of solving SIS via lattice reduction. """ + @staticmethod def _solve_for_delta_euclidean(params, d): # root_volume = params.q**(params.n/d) # delta = (params.length_bound / root_volume)**(1/(d - 1)) - root_volume = (params.n/d) * log(params.q, 2) - log_delta = (1/(d - 1)) * (log(params.length_bound, 2) - root_volume) + root_volume = (params.n / d) * log(params.q, 2) + log_delta = (1 / (d - 1)) * (log(params.length_bound, 2) - root_volume) return RR(2**log_delta) @staticmethod @@ -40,7 +41,7 @@ def _opt_sis_d(params): Optimizes SIS dimension for the given parameters, assuming the optimal d \approx sqrt(n*log(q)/log(delta)) """ - log_delta = log(params.length_bound, 2)**2 / (4 * params.n * log(params.q, 2)) + log_delta = log(params.length_bound, 2) ** 2 / (4 * params.n * log(params.q, 2)) d = sqrt(params.n * log(params.q, 2) / log_delta) return d @@ -71,8 +72,10 @@ def cost_euclidean( beta = d reduction_possible = False - lb = min(RR(sqrt(params.n * log(params.q))), RR(sqrt(d) * params.q**(params.n/d))) - return costf(red_cost_model, beta, d, predicate=params.length_bound > lb and reduction_possible) + lb = min(RR(sqrt(params.n * log(params.q))), RR(sqrt(d) * params.q ** (params.n / d))) + return costf( + red_cost_model, beta, d, predicate=params.length_bound > lb and reduction_possible + ) @staticmethod @cached_function @@ -121,7 +124,7 @@ def cost_infinity( vector_length = rho * sqrt(r[0]) # Find probability that all coordinates meet norm bound sigma = vector_length / sqrt(d_) - log_trial_prob = RR(d_*log(1 - 2*gaussian_cdf(0, sigma, -params.length_bound), 2)) + log_trial_prob = RR(d_ * log(1 - 2 * gaussian_cdf(0, sigma, -params.length_bound), 2)) else: # Dilithium style analysis # Find first non-q-vector in r @@ -142,10 +145,14 @@ def cost_infinity( gaussian_coords = max(idx_end - idx_start + 1, sieve_dim) sigma = vector_length / sqrt(gaussian_coords) - log_trial_prob = RR(log(1 - 2*gaussian_cdf(0, sigma, -params.length_bound), 2)*(gaussian_coords)) - log_trial_prob += RR(log((2*params.length_bound + 1)/params.q, 2)*(idx_start)) + log_trial_prob = RR( + log(1 - 2 * gaussian_cdf(0, sigma, -params.length_bound), 2) * (gaussian_coords) + ) + log_trial_prob += RR(log((2 * params.length_bound + 1) / params.q, 2) * (idx_start)) - probability = 2**min(0, log_trial_prob + RR(log(N, 2))) # expected number of solutions (max 1) + probability = 2 ** min( + 0, log_trial_prob + RR(log(N, 2)) + ) # expected number of solutions (max 1) ret = Cost() ret["rop"] = cost_red ret["red"] = bkz_cost["rop"] @@ -291,7 +298,9 @@ def __call__( elif params.norm == oo: tag = "infinity" else: - raise NotImplementedError("SIS attack estimation currently only supports euclidean and infinity norms") + raise NotImplementedError( + "SIS attack estimation currently only supports euclidean and infinity norms" + ) if tag == "infinity": red_shape_model = simulator_normalize(red_shape_model) From fb00e9aaf7cc4400ac485e1bd7bf9f9fd269850f Mon Sep 17 00:00:00 2001 From: "Martin R. Albrecht" Date: Wed, 7 Feb 2024 14:36:04 +0000 Subject: [PATCH 02/10] return gracefully if bad parameters are given --- estimator/sis_lattice.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/estimator/sis_lattice.py b/estimator/sis_lattice.py index 9109839..3236e0f 100644 --- a/estimator/sis_lattice.py +++ b/estimator/sis_lattice.py @@ -113,6 +113,9 @@ def cost_infinity( # Calculate the basis shape to aid in both styles of analysis d_ = d - zeta + if d_ < beta: + return Cost(rop=oo, mem=oo) + r = simulator(d=d_, n=d_ - params.n, q=params.q, beta=beta, xi=1, tau=False) # Cost the sampling of short vectors. From 0187a4744d14ec9a85816e4cb43f7b16b3f322a1 Mon Sep 17 00:00:00 2001 From: "Martin R. Albrecht" Date: Wed, 7 Feb 2024 14:36:26 +0000 Subject: [PATCH 03/10] loop zeta until m and not n --- estimator/sis_lattice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/estimator/sis_lattice.py b/estimator/sis_lattice.py index 3236e0f..58edd12 100644 --- a/estimator/sis_lattice.py +++ b/estimator/sis_lattice.py @@ -317,7 +317,7 @@ def __call__( ) if zeta is None: - with local_minimum(0, params.n, log_level=log_level) as it: + with local_minimum(0, params.m, log_level=log_level) as it: for zeta in it: it.update( f( From a053c00685bddcdeea6a68edd6b6a8e6a5136804 Mon Sep 17 00:00:00 2001 From: "Martin R. Albrecht" Date: Wed, 7 Feb 2024 14:36:42 +0000 Subject: [PATCH 04/10] pick tighter m --- estimator/sis_parameters.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/estimator/sis_parameters.py b/estimator/sis_parameters.py index 77d255b..28d265c 100644 --- a/estimator/sis_parameters.py +++ b/estimator/sis_parameters.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from dataclasses import dataclass -from sage.all import log, ceil +from sage.all import log, ceil, oo @dataclass @@ -19,7 +19,11 @@ class SISParameters: def __post_init__(self, **kwds): if not self.m: - self.m = ceil(self.n*log(self.q)) #: Set m to be the minimum required for a solution to exist. + #: Set m to be the minimum required for a solution to exist. + if self.norm == oo: + self.m = ceil(self.n * log(self.q, (2 * self.length_bound + 1))) + else: + self.m = ceil(self.n * log(self.q, 2)) @property def _homogeneous(self): From f2767f766b98303016fc378383d350b8cb737ca7 Mon Sep 17 00:00:00 2001 From: "Martin R. Albrecht" Date: Wed, 7 Feb 2024 14:37:25 +0000 Subject: [PATCH 05/10] import --- estimator/sis_lattice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/estimator/sis_lattice.py b/estimator/sis_lattice.py index 58edd12..1ee3d44 100644 --- a/estimator/sis_lattice.py +++ b/estimator/sis_lattice.py @@ -7,7 +7,7 @@ """ from functools import partial -from sage.all import oo, sqrt, log, RR, floor, cached_function +from sage.all import oo, sqrt, log, RR, floor, cached_function, ceil from .reduction import beta as betaf from .reduction import cost as costf from .util import local_minimum From 88d45329198da26168ad9863a956859c27ebe7d9 Mon Sep 17 00:00:00 2001 From: "Martin R. Albrecht" Date: Wed, 7 Feb 2024 14:37:37 +0000 Subject: [PATCH 06/10] skip "baseline cost" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit we struggle to establish the right ℓ_2 norm --- estimator/sis_lattice.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/estimator/sis_lattice.py b/estimator/sis_lattice.py index 1ee3d44..bd2220f 100644 --- a/estimator/sis_lattice.py +++ b/estimator/sis_lattice.py @@ -202,17 +202,19 @@ def cost_zeta( instance is treated as d-ζ. """ # step 0. establish baseline cost using worst case euclidean norm estimate - params_baseline = params.updated(norm=2) - baseline_cost = lattice( - params_baseline, - ignore_qary=ignore_qary, - red_shape_model=red_shape_model, - red_cost_model=red_cost_model, - log_level=log_level + 1, - **kwds, - ) - - Logging.log("sis_infinity", log_level, f"H0: {repr(baseline_cost)}") + # params_baseline = params.updated( + # norm=2, length_bound=2 * sqrt(params.m) * params.length_bound + # ) + # baseline_cost = lattice( + # params_baseline, + # ignore_qary=ignore_qary, + # red_shape_model=red_shape_model, + # red_cost_model=red_cost_model, + # log_level=log_level + 1, + # **kwds, + # ) + + # Logging.log("sis_infinity", log_level, f"H0: {repr(baseline_cost)}") f = partial( cls.cost_infinity, @@ -226,9 +228,7 @@ def cost_zeta( ) # step 1. optimize β - with local_minimum( - 40, baseline_cost["beta"] + 1, precision=2, log_level=log_level + 1 - ) as it: + with local_minimum(40, 1000 + 1, precision=2, log_level=log_level + 1) as it: for beta in it: it.update(f(beta)) for beta in it.neighborhood: From 6c8a3743931521941909f4e5093ddbb1200132dd Mon Sep 17 00:00:00 2001 From: "Martin R. Albrecht" Date: Wed, 7 Feb 2024 14:38:41 +0000 Subject: [PATCH 07/10] unused import --- estimator/sis_lattice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/estimator/sis_lattice.py b/estimator/sis_lattice.py index bd2220f..21f9be4 100644 --- a/estimator/sis_lattice.py +++ b/estimator/sis_lattice.py @@ -7,7 +7,7 @@ """ from functools import partial -from sage.all import oo, sqrt, log, RR, floor, cached_function, ceil +from sage.all import oo, sqrt, log, RR, floor, cached_function from .reduction import beta as betaf from .reduction import cost as costf from .util import local_minimum From 790fa8cbc75e4c0a81081bf29c6fd59b491c841f Mon Sep 17 00:00:00 2001 From: "Martin R. Albrecht" Date: Wed, 7 Feb 2024 14:44:20 +0000 Subject: [PATCH 08/10] that was a wee bit tight --- estimator/sis_parameters.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/estimator/sis_parameters.py b/estimator/sis_parameters.py index 28d265c..58086dd 100644 --- a/estimator/sis_parameters.py +++ b/estimator/sis_parameters.py @@ -21,9 +21,9 @@ def __post_init__(self, **kwds): if not self.m: #: Set m to be the minimum required for a solution to exist. if self.norm == oo: - self.m = ceil(self.n * log(self.q, (2 * self.length_bound + 1))) + self.m = 2 * ceil(self.n * log(self.q, (2 * self.length_bound + 1))) else: - self.m = ceil(self.n * log(self.q, 2)) + self.m = 2 * ceil(self.n * log(self.q, 2)) @property def _homogeneous(self): From 43f4bdf05b03320c5d59418d7067b24325d4944a Mon Sep 17 00:00:00 2001 From: "Martin R. Albrecht" Date: Wed, 7 Feb 2024 15:23:48 +0000 Subject: [PATCH 09/10] "fix" doctests --- estimator/sis.py | 14 ++++++++------ estimator/sis_lattice.py | 8 ++++---- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/estimator/sis.py b/estimator/sis.py index 3b4b21e..b8fda0d 100644 --- a/estimator/sis.py +++ b/estimator/sis.py @@ -8,14 +8,15 @@ from .sis_lattice import lattice from .sis_parameters import SISParameters as Parameters # noqa -from .conf import (red_cost_model as red_cost_model_default, - red_shape_model as red_shape_model_default) +from .conf import ( + red_cost_model as red_cost_model_default, + red_shape_model as red_shape_model_default, +) from .util import batch_estimate, f_name from .reduction import RC class Estimate: - def rough(self, params, jobs=1, catch_exceptions=True): """ This function makes the following somewhat routine assumptions: @@ -47,7 +48,8 @@ def rough(self, params, jobs=1, catch_exceptions=True): ) res_raw = res_raw[params] res = { - algorithm: v for algorithm, attack in algorithms.items() + algorithm: v + for algorithm, attack in algorithms.items() for k, v in res_raw.items() if f_name(attack) == k } @@ -91,8 +93,8 @@ def __call__( >>> _ = SIS.estimate(params) lattice :: rop: ≈2^47.0, red: ≈2^47.0, δ: 1.011391, β: 61, d: 276, tag: euclidean - >>> _ = SIS.estimate(params.updated(norm=oo), red_shape_model="cn11") - lattice :: rop: ≈2^43.6, red: ≈2^42.6, sieve: ≈2^42.7, β: 40, η: 67, ζ: 112, d: 750, ... + >>> _ = SIS.estimate(params.updated(length_bound=16, norm=oo), red_shape_model="cn11") + lattice :: rop: ≈2^65.9, red: ≈2^64.9, sieve: ≈2^64.9, β: 113, η: 142, ζ: 0, d: 2486, ... """ algorithms = {} diff --git a/estimator/sis_lattice.py b/estimator/sis_lattice.py index 21f9be4..60046e4 100644 --- a/estimator/sis_lattice.py +++ b/estimator/sis_lattice.py @@ -282,11 +282,11 @@ def __call__( >>> SIS.lattice(params) rop: ≈2^47.0, red: ≈2^47.0, δ: 1.011391, β: 61, d: 276, tag: euclidean - >>> SIS.lattice(params.updated(norm=oo), red_shape_model="lgsa") - rop: ≈2^43.6, red: ≈2^42.6, sieve: ≈2^42.7, β: 40, η: 67, ζ: 112, d: 750, prob: 1, ↻: 1, tag: infinity + >>> SIS.lattice(params.updated(norm=oo, length_bound=16), red_shape_model="lgsa") + rop: ≈2^61.0, red: ≈2^59.9, sieve: ≈2^60.1, β: 95, η: 126, ζ: 0, d: 2486, prob: 1, ↻: 1, tag: infinity - >>> SIS.lattice(params.updated(norm=oo), red_shape_model="cn11") - rop: ≈2^43.6, red: ≈2^42.6, sieve: ≈2^42.7, β: 40, η: 67, ζ: 112, d: 750, prob: 1, ↻: 1, tag: infinity + >>> SIS.lattice(params.updated(norm=oo, length_bound=16), red_shape_model="cn11") + rop: ≈2^65.9, red: ≈2^64.9, sieve: ≈2^64.9, β: 113, η: 142, ζ: 0, d: 2486, prob: 1, ↻: 1, tag: infinity The success condition for euclidean norm bound is derived by determining the root hermite factor required for BKZ to produce the required output. For infinity norm bounds, the success conditions are derived using a From 46e528d3acd4703a34f750b5531fc8c4a5e29c39 Mon Sep 17 00:00:00 2001 From: "Martin R. Albrecht" Date: Wed, 7 Feb 2024 15:35:20 +0000 Subject: [PATCH 10/10] revert this change, it's not needed --- estimator/sis_lattice.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/estimator/sis_lattice.py b/estimator/sis_lattice.py index 60046e4..43b4e92 100644 --- a/estimator/sis_lattice.py +++ b/estimator/sis_lattice.py @@ -202,19 +202,17 @@ def cost_zeta( instance is treated as d-ζ. """ # step 0. establish baseline cost using worst case euclidean norm estimate - # params_baseline = params.updated( - # norm=2, length_bound=2 * sqrt(params.m) * params.length_bound - # ) - # baseline_cost = lattice( - # params_baseline, - # ignore_qary=ignore_qary, - # red_shape_model=red_shape_model, - # red_cost_model=red_cost_model, - # log_level=log_level + 1, - # **kwds, - # ) - - # Logging.log("sis_infinity", log_level, f"H0: {repr(baseline_cost)}") + params_baseline = params.updated(norm=2) + baseline_cost = lattice( + params_baseline, + ignore_qary=ignore_qary, + red_shape_model=red_shape_model, + red_cost_model=red_cost_model, + log_level=log_level + 1, + **kwds, + ) + + Logging.log("sis_infinity", log_level, f"H0: {repr(baseline_cost)}") f = partial( cls.cost_infinity, @@ -228,7 +226,9 @@ def cost_zeta( ) # step 1. optimize β - with local_minimum(40, 1000 + 1, precision=2, log_level=log_level + 1) as it: + with local_minimum( + 40, baseline_cost["beta"] + 1, precision=2, log_level=log_level + 1 + ) as it: for beta in it: it.update(f(beta)) for beta in it.neighborhood: