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

Add overstretched NTRU estimation functionality #86

Merged
merged 15 commits into from
Nov 1, 2023
Merged
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
1 change: 1 addition & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ At present, this estimator is maintained by Martin Albrecht. Contributors are:
- Fernando Virdia
- Florian Göpfert
- Hamish Hunt
- Hunter Kippen
- James Owen
- Léo Ducas
- Markus Schmidt
Expand Down
3 changes: 3 additions & 0 deletions docs/api_doc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ API Reference
estimator.lwe_primal
estimator.lwe_dual
estimator.lwe
estimator.ntru_parameters
estimator.ntru_primal
estimator.ntru
estimator.gb
estimator.nd
estimator.prob
Expand Down
4 changes: 3 additions & 1 deletion docs/references.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ References
.. [AC:AGPS20] Albrecht, M. R., Gheorghiu, V., Postlethwaite, E. W., & Schanck, J. M. (2020). Estimating quantum speedups for lattice sieves. In S. Moriai, & H. Wang, ASIACRYPT 2020, Part II (pp. 583–613). : Springer, Heidelberg.
.. [AC:AGVW17] Martin R. Albrecht, Florian Göpfert, Fernando Virdia & Thomas Wunderer. Revisiting the expected cost of solving uSVP and applications to LWE. In T. Takagi, & T. Peyrin, ASIACRYPT 2017, Part I (pp. 297–322). : Springer, Heidelberg.
.. [AC:CheNgu11] Yuanmi Chen & Phong Q. Nguyen. BKZ 2.0: better lattice security estimates. In D. H. Lee, & X. Wang, ASIACRYPT 2011 (pp. 1–20): Springer, Heidelberg.
.. [AC:DucWoe21] Ducas, L., van Woerden, W. (2021). NTRU Fatigue: How Stretched is Overstretched?. In: Tibouchi, M., Wang, H. (eds) Advances in Cryptology – ASIACRYPT 2021. ASIACRYPT 2021. Lecture Notes in Computer Science(), vol 13093. Springer, Cham. https://doi.org/10.1007/978-3-030-92068-5_1
.. [AC:GuoJoh21] Qian Guo, Thomas Johansson. Faster Dual Lattice Attacks for Solving LWE with Applications to CRYSTALS. In International Conference on the Theory and Application of Cryptology and Information Security (pp. 33-62). Springer, Cham.
.. [ACISP:BaiGal14] Shi Bai & Steven D. Galbraith. Lattice decoding attacks on binary LWE. In W. Susilo, & Y. Mu, ACISP 14 (pp. 322–337). : Springer, Heidelberg.
.. [C:ABFKSW20] Martin R. Albrecht, Shi Bai, Pierre-Alain Fouque, Paul Kirchner, Damien Stehlé and Weiqiang Wen. Faster Enumeration-based Lattice Reduction: Root Hermite Factor $beta^{1/(2k)}$ in Time $beta^{beta/8 + o(beta)}$. CRYPTO 2020.
Expand All @@ -15,6 +16,7 @@ References
.. [CheNgu12] Yuanmi Chen and Phong Q. Nguyen. BKZ 2.0: Better lattice security estimates (Full Version). 2012. http://www.di.ens.fr/~ychen/research/Full_BKZ.pdf
.. [EC:Albrecht17] Albrecht, M. R. (2017). On dual lattice attacks against small-secret LWE and parameter choices in HElib and SEAL. In J. Coron, & J. B. Nielsen, EUROCRYPT 2017, Part II (pp. 103–129). : Springer, Heidelberg.
.. [EC:Ducas18] Léo Ducas (2018). Shortest vector from lattice sieving: A few dimensions for free. In J. B. Nielsen, & V. Rijmen, EUROCRYPT 2018, Part I (pp. 125–145). : Springer, Heidelberg.
.. [EC:KirFou17] Kirchner, P., Fouque, PA. (2017). Revisiting Lattice Attacks on Overstretched NTRU Parameters. In: Coron, JS., Nielsen, J. (eds) Advances in Cryptology – EUROCRYPT 2017. EUROCRYPT 2017. Lecture Notes in Computer Science(), vol 10210. Springer, Cham. https://doi.org/10.1007/978-3-319-56620-7_1
.. [EPRINT:CHHS19] Cheon, J.H., Hhan, M., Hong, S. and Son, Y., 2019. A hybrid of dual and meet-in-the-middle attack on sparse and ternary secret LWE. IEEE Access, 7, pp.89497-89506. https://ia.cr/2019/1114pri
.. [EPRINT:LaaMosPol14] Thijs Laarhoven, Michele Mosca, & Joop van de Pol. Finding shortest lattice vectors faster using quantum search. Cryptology ePrint Archive, Report 2014/907, 2014. https://eprint.iacr.org/2014/907.
.. [EPRINT:SonChe19] Son, Y. and Cheon, J.H., 2019. Revisiting the Hybrid Attack on sparse abd ternary LWE. Workshop on Applied Homomorphic Cryptography, WAHC2019.
Expand All @@ -32,4 +34,4 @@ References
.. [SAC:AlbCurWun19] Albrecht, M. R., Curtis, B. R., & Wunderer, T.. Exploring trade-offs in batch bounded distance decoding. In K. G. Paterson, & D. Stebila, SAC 2019 (pp. 467–491). : Springer, Heidelberg.
.. [SODA:BDGL16] Becker, A., Ducas, L., Gama, N., & Laarhoven, T. (2016). New directions in nearest neighbor searching with applications to lattice sieving. In SODA 2016, (pp. 10–24).
.. [Schnorr03] Claus-Peter Schnorr. Lattice Reduction by Random Sampling and Birthday Methods. In: STACS2003, 20th Annual Symposium on Theoretical Aspects of Computer Science, Berlin, Germany, February 27 - March 1, 2003, Proceedings. Ed. by Helmut Alt and Michel Habib. Vol. 2607. Lecture Notes in Computer Science. Springer, 2003, pp. 145–156.doi:10.1007/3-540-36494-3_14. url: http://dx.doi.org/10.1007/3-540-36494-3_14.
.. [USENIX:ADPS16] Edem Alkim, Léo Ducas, Thomas Pöppelmann, & Peter Schwabe (2016). Post-quantum key exchange - A New Hope. In T. Holz, & S. Savage, 25th USENIX Security Symposium, USENIX Security 16 (pp. 327–343). USENIX Association.
.. [USENIX:ADPS16] Edem Alkim, Léo Ducas, Thomas Pöppelmann, & Peter Schwabe (2016). Post-quantum key exchange - A New Hope. In T. Holz, & S. Savage, 25th USENIX Security Symposium, USENIX Security 16 (pp. 327–343). USENIX Association.
18 changes: 9 additions & 9 deletions docs/schemes/nist-pqc-round-3.rst
Original file line number Diff line number Diff line change
Expand Up @@ -60,30 +60,30 @@ NIST PQC Round 3 Finalists

>>> from estimator import *
>>> schemes.NTRUHPS2048509Enc
LWEParameters(n=508, q=2048, Xs=D(σ=0.82), Xe=D(σ=0.71), m=508, tag='NTRUHPS2048509Enc')
>>> LWE.primal_bdd(schemes.NTRUHPS2048509Enc)
NTRUParameters(n=508, q=2048, Xs=D(σ=0.82), Xe=D(σ=0.71), m=508, tag='NTRUHPS2048509Enc', ntru_type='matrix')
>>> NTRU.primal_bdd(schemes.NTRUHPS2048509Enc)
rop: ≈2^131.1, red: ≈2^130.1, svp: ≈2^130.2, β: 357, η: 390, d: 916, tag: bdd

::

>>> from estimator import *
>>> schemes.NTRUHPS2048677Enc
LWEParameters(n=676, q=2048, Xs=D(σ=0.82), Xe=D(σ=0.61), m=676, tag='NTRUHPS2048677Enc')
>>> LWE.primal_bdd(schemes.NTRUHPS2048677Enc)
NTRUParameters(n=676, q=2048, Xs=D(σ=0.82), Xe=D(σ=0.61), m=676, tag='NTRUHPS2048677Enc', ntru_type='matrix')
>>> NTRU.primal_bdd(schemes.NTRUHPS2048677Enc)
rop: ≈2^170.8, red: ≈2^169.6, svp: ≈2^169.9, β: 498, η: 533, d: 1179, tag: bdd

::

>>> from estimator import *
>>> schemes.NTRUHPS4096821Enc
LWEParameters(n=820, q=4096, Xs=D(σ=0.82), Xe=D(σ=0.79), m=820, tag='NTRUHPS4096821Enc')
>>> LWE.primal_bdd(schemes.NTRUHPS4096821Enc)
NTRUParameters(n=820, q=4096, Xs=D(σ=0.82), Xe=D(σ=0.79), m=820, tag='NTRUHPS4096821Enc', ntru_type='matrix')
>>> NTRU.primal_bdd(schemes.NTRUHPS4096821Enc)
rop: ≈2^199.7, red: ≈2^198.7, svp: ≈2^198.6, β: 601, η: 636, d: 1485, tag: bdd

::

>>> from estimator import *
>>> schemes.NTRUHRSS701Enc
LWEParameters(n=700, q=8192, Xs=D(σ=0.82), Xe=D(σ=0.82), m=700, tag='NTRUHRSS701')
>>> LWE.primal_bdd(schemes.NTRUHRSS701Enc)
rop: ≈2^158.9, red: ≈2^157.9, svp: ≈2^158.0, β: 455, η: 490, d: 1294, tag: bdd
NTRUParameters(n=700, q=8192, Xs=D(σ=0.82), Xe=D(σ=0.82), m=700, tag='NTRUHRSS701', ntru_type='matrix')
>>> NTRU.primal_bdd(schemes.NTRUHRSS701Enc)
rop: ≈2^158.7, red: ≈2^157.7, svp: ≈2^157.7, β: 454, η: 489, d: 1306, tag: bdd
3 changes: 2 additions & 1 deletion estimator/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# -*- coding: utf-8 -*-

__all__ = ['ND', 'Logging', 'RC', 'Simulator', 'LWE', 'schemes']
__all__ = ['ND', 'Logging', 'RC', 'Simulator', 'LWE', 'NTRU', 'schemes']

from .nd import NoiseDistribution as ND
from .io import Logging
from .reduction import RC
from . import simulator as Simulator
from . import lwe as LWE
from . import ntru as NTRU
from . import schemes
8 changes: 7 additions & 1 deletion estimator/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@
Default values.
"""

from .reduction import RC
from .simulator import GSA
from .reduction import RC
from sage.all import exp

red_cost_model = RC.MATZOV
red_cost_model_classical_poly_space = RC.ABLR21
red_shape_model = "gsa"
red_simulator = GSA
mitm_opt = "analytical"
max_n_cache = 10000


def ntru_fatigue_lb(n):
return int((n**2.484)/exp(6))
4 changes: 4 additions & 0 deletions estimator/lwe_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ def __post_init__(self, **kwds):
self.Xe = copy(self.Xe)
self.Xe.n = self.m

@property
def _homogeneous(self):
return False

def normalize(self):
"""
EXAMPLES:
Expand Down
58 changes: 45 additions & 13 deletions estimator/lwe_primal.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,16 @@ def _solve_for_d(params, m, beta, tau, xi):
# Find the smallest d ∈ [n,m] s.t. a*d^2 + b*d + c >= 0
delta = deltaf(beta)
a = -log(delta)
C = log(params.Xe.stddev**2 * (beta - 1) + tau**2) / 2.0

if not tau:
C = log(params.Xe.stddev**2 * (beta - 1)) / 2.0
c = params.n * log(xi) - (params.n + 1) * log(params.q)

else:
C = log(params.Xe.stddev**2 * (beta - 1) + tau**2) / 2.0
c = log(tau) + params.n * log(xi) - (params.n + 1) * log(params.q)

b = log(delta) * (2 * beta - 1) + log(params.q) - C
c = log(tau) + params.n * log(xi) - (params.n + 1) * log(params.q)
n = params.n
if a * n * n + b * n + c >= 0: # trivial case
return n
Expand Down Expand Up @@ -87,18 +94,30 @@ def cost_gsa(
xi = PrimalUSVP._xi_factor(params.Xs, params.Xe)
m = min(2 * ceil(sqrt(params.n * log(params.q) / log(delta))), m)
tau = params.Xe.stddev if tau is None else tau
# Account for homogeneous instances
if params._homogeneous:
tau = False # Tau false ==> instance is homogeneous

d = PrimalUSVP._solve_for_d(params, m, beta, tau, xi) if d is None else d
# if d == β we assume one SVP call, otherwise poly calls. This makes the cost curve jump, so
# we avoid it here.
if d == beta and d < m:
d += 1
assert d <= m + 1

lhs = log(sqrt(params.Xe.stddev**2 * (beta - 1) + tau**2))
rhs = RR(
log(delta) * (2 * beta - d - 1)
+ (log(tau) + log(xi) * params.n + log(params.q) * (d - params.n - 1)) / d
)
if not tau:
lhs = log(sqrt(params.Xe.stddev**2 * (beta - 1)))
rhs = RR(
log(delta) * (2 * beta - d - 1)
+ (log(xi) * params.n + log(params.q) * (d - params.n - 1)) / d
)

else:
lhs = log(sqrt(params.Xe.stddev**2 * (beta - 1) + tau**2))
rhs = RR(
log(delta) * (2 * beta - d - 1)
+ (log(tau) + log(xi) * params.n + log(params.q) * (d - params.n - 1)) / d
)

return costf(red_cost_model, beta, d, predicate=lhs <= rhs)

Expand All @@ -120,8 +139,18 @@ def cost_simulator(
xi = PrimalUSVP._xi_factor(params.Xs, params.Xe)
tau = params.Xe.stddev if tau is None else tau

if params._homogeneous:
tau = False
d -= 1 # Remove extra dimension in homogeneous instances

r = simulator(d=d, n=params.n, q=params.q, beta=beta, xi=xi, tau=tau)
lhs = params.Xe.stddev**2 * (beta - 1) + tau**2

if not tau:
lhs = params.Xe.stddev**2 * (beta - 1)

else:
lhs = params.Xe.stddev**2 * (beta - 1) + tau**2

predicate = r[d - beta] > lhs

return costf(red_cost_model, beta, d, predicate=predicate)
Expand Down Expand Up @@ -174,10 +203,8 @@ def __call__(

"""
params = LWEParameters.normalize(params)

# allow for a larger embedding lattice dimension: Bai and Galbraith
m = params.m + params.n if params.Xs <= params.Xe else params.m

if red_shape_model == "gsa":
with local_minimum(40, max(2 * params.n, 41), precision=5) as it:
for beta in it:
Expand Down Expand Up @@ -311,12 +338,17 @@ def cost(
delta = deltaf(beta)
d = min(ceil(sqrt(params.n * log(params.q) / log(delta))), m) + 1
d -= zeta
xi = PrimalUSVP._xi_factor(params.Xs, params.Xe)

xi = PrimalUSVP._xi_factor(params.Xs, params.Xe)
tau = 1
# 1. Simulate BKZ-β
# TODO: pick τ
# TODO: pick τ as non default value

if params._homogeneous:
tau = False
d -= 1

r = simulator(d, params.n - zeta, params.q, beta, xi=xi, dual=True)
r = simulator(d, params.n - zeta, params.q, beta, xi=xi, tau=tau, dual=True)

bkz_cost = costf(red_cost_model, beta, d)

Expand Down
Loading
Loading