lattice-crypto-attacks

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

SKILL: Lattice-Based Cryptanalysis — Expert Attack Playbook

SKILL:基于格的密码分析——专家攻击指南

AI LOAD INSTRUCTION: Expert lattice techniques for CTF and cryptanalysis. Covers LLL/BKZ reduction, Coppersmith's method (univariate and multivariate), Hidden Number Problem for DSA/ECDSA nonce recovery, knapsack attacks, and NTRU analysis. Base models often fail to construct the correct attack lattice (wrong dimensions, missing scaling factors) or misapply Coppersmith bounds.
AI加载说明:适用于CTF和密码分析的专业格技术。涵盖LLL/BKZ规约、Coppersmith方法(单变量和多变量)、用于DSA/ECDSA随机数恢复的隐藏数问题、背包攻击以及NTRU分析。基础模型通常无法构建正确的攻击格(维度错误、缺少缩放因子)或者错误应用Coppersmith边界。

0. RELATED ROUTING

0. 相关导航

  • rsa-attack-techniques for RSA-specific attacks that use lattice methods (Coppersmith, Boneh-Durfee)
  • symmetric-cipher-attacks for LCG state recovery via lattice
  • classical-cipher-analysis when lattice methods apply to classical cipher analysis
  • rsa-attack-techniques 包含使用格方法的RSA专项攻击(Coppersmith、Boneh-Durfee)
  • symmetric-cipher-attacks 包含通过格方法恢复LCG状态的内容
  • classical-cipher-analysis 适用于格方法可应用于古典密码分析的场景

Quick application guide

快速应用指南

Problem TypeLattice TechniqueKey Parameter
RSA small rootsCoppersmith (LLL on polynomial lattice)Root bound X < N^(1/e)
RSA small dBoneh-Durfee (multivariate Coppersmith)d < N^0.292
DSA/ECDSA nonce biasHidden Number Problem → CVPBias bits known
Knapsack cipherLow-density lattice attackDensity < 0.9408
LCG truncated outputCVP on recurrence latticeUnknown bits per output
Subset sumLLL reduction on knapsack latticeElement size vs count
NTRU key recoveryLattice reduction on NTRU latticeDimension and key size

问题类型格技术关键参数
RSA小根Coppersmith(多项式格上的LLL规约)根边界 X < N^(1/e)
RSA小私钥dBoneh-Durfee(多变量Coppersmith)d < N^0.292
DSA/ECDSA随机数偏差隐藏数问题 → CVP已知偏差比特数
背包密码低密度格攻击密度 < 0.9408
LCG截断输出递推格上的CVP每个输出的未知比特数
子集和背包格上的LLL规约元素大小与数量的关系
NTRU密钥恢复NTRU格上的格规约维度与密钥大小

1. LATTICE FUNDAMENTALS

1. 格基础

1.1 Definitions

1.1 定义

A lattice L is the set of all integer linear combinations of basis vectors:
L = { a₁·b₁ + a₂·b₂ + ... + aₙ·bₙ | aᵢ ∈ ℤ }
where b₁, ..., bₙ are linearly independent vectors in ℝᵐ.
Key problems:
  • SVP (Shortest Vector Problem): Find the shortest non-zero vector in L
  • CVP (Closest Vector Problem): Given target t, find v ∈ L closest to t
  • SVP is NP-hard in general, but LLL finds an approximately short vector in polynomial time
L 是基向量所有整数线性组合的集合:
L = { a₁·b₁ + a₂·b₂ + ... + aₙ·bₙ | aᵢ ∈ ℤ }
其中 b₁, ..., bₙ 是 ℝᵐ 中的线性无关向量。
核心问题
  • SVP(最短向量问题):找到L中最短的非零向量
  • CVP(最近向量问题):给定目标向量t,找到L中最接近t的向量v
  • 一般情况下SVP是NP难问题,但LLL算法可以在多项式时间内找到近似最短向量

1.2 Lattice Quality Metrics

1.2 格质量指标

Determinant: det(L) = |det(B)| where B is the basis matrix
Gaussian heuristic: shortest vector ≈ √(n/(2πe)) · det(L)^(1/n)

行列式: det(L) = |det(B)|,其中B是基矩阵
高斯启发式: 最短向量 ≈ √(n/(2πe)) · det(L)^(1/n)

2. LLL ALGORITHM

2. LLL算法

2.1 What LLL Does

2.1 LLL的作用

Takes a lattice basis B and produces a reduced basis B' where:
  • Vectors are nearly orthogonal
  • First vector is approximately short (within 2^((n-1)/2) factor of SVP)
  • Runs in polynomial time: O(n^5 · d · log³ B) where d = dimension, B = max entry size
接收格基B,生成规约基 B',满足:
  • 向量几乎正交
  • 第一个向量是近似最短向量(与SVP的误差在2^((n-1)/2)因子以内)
  • 多项式时间运行:O(n^5 · d · log³ B),其中d是维度,B是矩阵元素最大值

2.2 SageMath Usage

2.2 SageMath使用示例

python
undefined
python
undefined

SageMath

SageMath

M = matrix(ZZ, [ [1, 0, 0, large_value_1], [0, 1, 0, large_value_2], [0, 0, 1, large_value_3], [0, 0, 0, modulus], ])
L = M.LLL()
M = matrix(ZZ, [ [1, 0, 0, large_value_1], [0, 1, 0, large_value_2], [0, 0, 1, large_value_3], [0, 0, 0, modulus], ])
L = M.LLL()

Short vectors in L reveal the solution

L中的短向量对应解

short_vector = L[0] # first row is typically shortest
undefined
short_vector = L[0] # 第一行通常是最短向量
undefined

2.3 Python (fpylll)

2.3 Python(fpylll)使用示例

python
from fpylll import IntegerMatrix, LLL

n = 4
A = IntegerMatrix(n, n)
python
from fpylll import IntegerMatrix, LLL

n = 4
A = IntegerMatrix(n, n)

Fill matrix A...

填充矩阵A...

A[0] = (1, 0, 0, large_value_1) A[1] = (0, 1, 0, large_value_2) A[2] = (0, 0, 1, large_value_3) A[3] = (0, 0, 0, modulus)
LLL.reduction(A) print(A[0]) # shortest vector

---
A[0] = (1, 0, 0, large_value_1) A[1] = (0, 1, 0, large_value_2) A[2] = (0, 0, 1, large_value_3) A[3] = (0, 0, 0, modulus)
LLL.reduction(A) print(A[0]) # 最短向量

---

3. BKZ (BLOCK KORKINE-ZOLOTAREV)

3. BKZ(BLOCK KORKINE-ZOLOTAREV)算法

3.1 Comparison with LLL

3.1 与LLL的对比

PropertyLLLBKZ-β
Quality2^((n-1)/2) approximation2^(n/(β-1)) approximation
SpeedPolynomialExponential in β
Block sizeFixed (2)Configurable β
Best forQuick reductionHigh-quality reduction
属性LLLBKZ-β
规约质量2^((n-1)/2) 近似比2^(n/(β-1)) 近似比
速度多项式时间随β指数级增长
块大小固定为2可配置β
适用场景快速规约高质量规约

3.2 Usage

3.2 使用示例

python
undefined
python
undefined

SageMath

SageMath

M = matrix(ZZ, [...]) L = M.BKZ(block_size=20) # β = 20
M = matrix(ZZ, [...]) L = M.BKZ(block_size=20) # β = 20

fpylll

fpylll

from fpylll import BKZ BKZ.reduction(A, BKZ.Param(block_size=20))

Rule of thumb: start with LLL, increase to BKZ if needed. BKZ block size 20-40 is usually sufficient for CTF.

---
from fpylll import BKZ BKZ.reduction(A, BKZ.Param(block_size=20))

经验法则:先使用LLL,若失败再升级为BKZ。CTF场景下BKZ块大小20-40通常足够。

---

4. COPPERSMITH'S METHOD

4. COPPERSMITH方法

4.1 Univariate Case

4.1 单变量场景

Given f(x) ≡ 0 (mod N) with small root |x₀| < X, find x₀.
Bound: X < N^(1/d) where d = degree of f.
python
undefined
给定f(x) ≡ 0 (mod N),存在小根 |x₀| < X,求解x₀。
边界:X < N^(1/d),其中d是f的次数。
python
undefined

SageMath — built-in small_roots

SageMath — 内置small_roots方法

N = ... R.<x> = PolynomialRing(Zmod(N)) f = x^3 + ax^2 + bx + c # known polynomial roots = f.small_roots(X=2^100, beta=1.0, epsilon=1/30)

**Parameters**:
- `X`: upper bound on the root
- `beta`: N = p^beta (beta=1.0 for modular root of N itself; beta=0.5 for root mod unknown factor p ≈ √N)
- `epsilon`: smaller = better results but slower (try 1/30 to 1/100)
N = ... R.<x> = PolynomialRing(Zmod(N)) f = x^3 + ax^2 + bx + c # 已知多项式 roots = f.small_roots(X=2^100, beta=1.0, epsilon=1/30)

**参数说明**:
- `X`:根的上边界
- `beta`:N = p^beta(beta=1.0对应模N本身的根;beta=0.5对应模未知因子p ≈ √N的根)
- `epsilon`:值越小效果越好但速度越慢,建议取1/30到1/100之间

4.2 Stereotyped Message Attack (RSA)

4.2 固定格式消息攻击(RSA)

python
undefined
python
undefined

SageMath

SageMath

n, e, c = ... # RSA parameters known_msb = ... # known upper portion of message
R.<x> = PolynomialRing(Zmod(n)) f = (known_msb + x)^e - c
n, e, c = ... # RSA参数 known_msb = ... # 消息已知的高位部分
R.<x> = PolynomialRing(Zmod(n)) f = (known_msb + x)^e - c

x represents the unknown lower bits

x代表未知的低位比特

X = 2^(unknown_bit_count) roots = f.small_roots(X=X, beta=1.0) if roots: m = known_msb + int(roots[0])
undefined
X = 2^(unknown_bit_count) roots = f.small_roots(X=X, beta=1.0) if roots: m = known_msb + int(roots[0])
undefined

4.3 Partial Key Exposure (Factor p)

4.3 部分密钥泄露(分解p)

Known MSBs of p:
p = p_known + x
where x is small.
python
undefined
已知p的高位:
p = p_known + x
,其中x很小。
python
undefined

SageMath

SageMath

n = ... p_known = ... # known upper bits of p
R.<x> = PolynomialRing(Zmod(n)) f = p_known + x roots = f.small_roots(X=2^unknown_bits, beta=0.5)
n = ... p_known = ... # p已知的高位比特
R.<x> = PolynomialRing(Zmod(n)) f = p_known + x roots = f.small_roots(X=2^unknown_bits, beta=0.5)

beta=0.5 because p ≈ √n

beta=0.5因为p ≈ √n

if roots: p = p_known + int(roots[0]) q = n // p
undefined
if roots: p = p_known + int(roots[0]) q = n // p
undefined

4.4 Multivariate Coppersmith (Howgrave-Graham)

4.4 多变量Coppersmith(Howgrave-Graham)

For f(x, y) ≡ 0 (mod N):
  • No polynomial-time algorithm guaranteed
  • Heuristic methods work in practice
  • Used in Boneh-Durfee for RSA small d
python
undefined
针对f(x, y) ≡ 0 (mod N)的场景:
  • 没有保证多项式时间的算法
  • 启发式方法在实践中有效
  • 用于Boneh-Durfee算法破解RSA小私钥d
python
undefined

SageMath — Boneh-Durfee

SageMath — Boneh-Durfee

e*d ≡ 1 (mod phi) where phi = (p-1)(q-1)

e*d ≡ 1 (mod phi) 其中 phi = (p-1)(q-1)

Rewrite: ed = 1 + k((n+1) - (p+q))

重写为: ed = 1 + k((n+1) - (p+q))

Let x = k, y = (p+q), both small relative to n

令x = k, y = (p+q),二者都远小于n

R.<x, y> = PolynomialRing(ZZ) A = (n + 1) // 2 f = 1 + x * (A + y) # mod e
R.<x, y> = PolynomialRing(ZZ) A = (n + 1) // 2 f = 1 + x * (A + y) # mod e

Build shift polynomials and construct lattice

构建平移多项式并构造格

Apply LLL to find small (x₀, y₀)

应用LLL寻找小根(x₀, y₀)


---

---

5. HIDDEN NUMBER PROBLEM (HNP) — DSA/ECDSA NONCE RECOVERY

5. 隐藏数问题(HNP)—— DSA/ECDSA随机数恢复

5.1 Problem Statement

5.1 问题描述

Given: signatures (rᵢ, sᵢ) where nonces kᵢ have known bias (leaked MSBs or LSBs).
DSA equation:
s = k⁻¹(H(m) + xr) mod q
Rearranged:
k = s⁻¹(H(m) + xr) mod q
If partial bits of k are known: reduces to CVP on a lattice.
给定:签名(rᵢ, sᵢ),其中随机数kᵢ存在已知偏差(泄露高位或低位比特)。
DSA等式:
s = k⁻¹(H(m) + xr) mod q
整理后:
k = s⁻¹(H(m) + xr) mod q
如果k的部分比特已知:可归约为格上的CVP问题。

5.2 Attack Setup

5.2 攻击实现

python
undefined
python
undefined

SageMath

SageMath

def ecdsa_nonce_attack(signatures, q, known_bits, bit_position='msb'): """ signatures: list of (r, s, hash, known_nonce_bits) q: curve order known_bits: number of known bits per nonce """ n = len(signatures)
# Build lattice
B = 2^(q.nbits() - known_bits)  # bound on unknown part
M = matrix(QQ, n + 2, n + 2)

for i in range(n):
    r_i, s_i, h_i, a_i = signatures[i]
    t_i = Integer(inverse_mod(s_i, q) * r_i % q)
    u_i = Integer(inverse_mod(s_i, q) * h_i % q)

    M[i, i] = q
    M[n, i] = t_i
    M[n+1, i] = u_i - a_i  # a_i = known nonce bits

M[n, n] = B / q
M[n+1, n+1] = B

# LLL reduction
L = M.LLL()

# Find row containing the private key x
for row in L:
    x_candidate = Integer(row[n] * q / B) % q
    # Verify x_candidate against one signature
    if verify_private_key(x_candidate, signatures[0], q):
        return x_candidate

return None
undefined
def ecdsa_nonce_attack(signatures, q, known_bits, bit_position='msb'): """ signatures: 签名列表,格式为(r, s, hash, known_nonce_bits) q: 椭圆曲线阶 known_bits: 每个随机数的已知比特数 """ n = len(signatures)
# 构建格
B = 2^(q.nbits() - known_bits)  # 未知部分的边界
M = matrix(QQ, n + 2, n + 2)

for i in range(n):
    r_i, s_i, h_i, a_i = signatures[i]
    t_i = Integer(inverse_mod(s_i, q) * r_i % q)
    u_i = Integer(inverse_mod(s_i, q) * h_i % q)

    M[i, i] = q
    M[n, i] = t_i
    M[n+1, i] = u_i - a_i  # a_i = 随机数已知比特

M[n, n] = B / q
M[n+1, n+1] = B

# LLL规约
L = M.LLL()

# 查找包含私钥x的行
for row in L:
    x_candidate = Integer(row[n] * q / B) % q
    # 用一个签名验证x候选值
    if verify_private_key(x_candidate, signatures[0], q):
        return x_candidate

return None
undefined

5.3 Practical Nonce Bias Sources

5.3 常见随机数偏差来源

SourceLeaked BitsRequired Signatures
MSB bias (always 0)1 bit~100 signatures
k generated with wrong lengthVariable~50 signatures
Timing side channel1-4 bits20-100 signatures
Insecure PRNGManyFew
Reused nonce (k₁ = k₂)All2 signatures
For reused nonce (simplest case):
python
def ecdsa_reused_nonce(r, s1, s2, h1, h2, q):
    """Recover private key when nonce k is reused."""
    # s1 - s2 = k⁻¹(h1 - h2) mod q  (since r is same)
    k = ((h1 - h2) * inverse_mod(s1 - s2, q)) % q
    x = ((s1 * k - h1) * inverse_mod(r, q)) % q
    return x, k

来源泄露比特数所需签名数量
高位偏差(恒为0)1比特~100个签名
k生成时长度错误可变~50个签名
计时侧信道1-4比特20-100个签名
不安全PRNG多比特少量
随机数重用(k₁ = k₂)全部比特2个签名
针对随机数重用(最简单场景):
python
def ecdsa_reused_nonce(r, s1, s2, h1, h2, q):
    """当随机数k重用时恢复私钥。"""
    # s1 - s2 = k⁻¹(h1 - h2) mod q (因为r相同)
    k = ((h1 - h2) * inverse_mod(s1 - s2, q)) % q
    x = ((s1 * k - h1) * inverse_mod(r, q)) % q
    return x, k

6. KNAPSACK / SUBSET SUM ATTACKS

6. 背包/子集和攻击

6.1 Low-Density Attack

6.1 低密度攻击

Knapsack: given weights a₁,...,aₙ and target S, find x₁,...,xₙ ∈ {0,1} such that Σxᵢaᵢ = S.
Density d = n / max(log₂ aᵢ). If d < 0.9408, lattice attack works.
python
undefined
背包问题:给定权重a₁,...,aₙ和目标S,寻找x₁,...,xₙ ∈ {0,1},满足Σxᵢaᵢ = S。
密度 d = n / max(log₂ aᵢ)。如果d < 0.9408,格攻击有效。
python
undefined

SageMath

SageMath

def knapsack_lattice(weights, target): """Solve subset sum via LLL lattice attack.""" n = len(weights)
# Build lattice (Lagarias-Odlyzko style)
N = ceil(sqrt(n) / 2)  # scaling factor
M = matrix(ZZ, n + 1, n + 1)

for i in range(n):
    M[i, i] = 1
    M[i, n] = N * weights[i]
M[n, n] = N * target

# Alternative: CJLOSS embedding
M2 = matrix(ZZ, n + 1, n + 2)
for i in range(n):
    M2[i, i] = 1
    M2[i, n + 1] = N * weights[i]
M2[n, n] = 1
M2[n, n + 1] = N * (-target)

L = M2.LLL()

# Look for short vector with entries in {0, 1, -1}
for row in L:
    if all(v in (0, 1) for v in row[:n]):
        solution = list(row[:n])
        if sum(solution[i] * weights[i] for i in range(n)) == target:
            return solution

return None

---
def knapsack_lattice(weights, target): """通过LLL格攻击求解子集和问题。""" n = len(weights)
# 构建格(Lagarias-Odlyzko风格)
N = ceil(sqrt(n) / 2)  # 缩放因子
M = matrix(ZZ, n + 1, n + 1)

for i in range(n):
    M[i, i] = 1
    M[i, n] = N * weights[i]
M[n, n] = N * target

# 替代方案:CJLOSS嵌入
M2 = matrix(ZZ, n + 1, n + 2)
for i in range(n):
    M2[i, i] = 1
    M2[i, n + 1] = N * weights[i]
M2[n, n] = 1
M2[n, n + 1] = N * (-target)

L = M2.LLL()

# 查找元素为{0, 1, -1}的短向量
for row in L:
    if all(v in (0, 1) for v in row[:n]):
        solution = list(row[:n])
        if sum(solution[i] * weights[i] for i in range(n)) == target:
            return solution

return None

---

7. NTRU CRYPTANALYSIS

7. NTRU密码分析

7.1 NTRU Lattice

7.1 NTRU格

python
undefined
python
undefined

SageMath

SageMath

def ntru_lattice_attack(h, q, N): """ Construct NTRU lattice for key recovery. h = public key polynomial (mod q) q = modulus N = dimension """ # NTRU lattice: # | qI 0 | # | H I | # where H is the circulant matrix of h
H = matrix(ZZ, N, N)
for i in range(N):
    for j in range(N):
        H[i, j] = h[(j - i) % N]

M = block_matrix([
    [q * identity_matrix(N), zero_matrix(N)],
    [H, identity_matrix(N)]
])

L = M.LLL()

# Short vector in reduced basis = (f, g) private key
for row in L:
    f = vector(row[:N])
    g = vector(row[N:])
    if f.norm() < q and g.norm() < q:
        return f, g

return None

---
def ntru_lattice_attack(h, q, N): """ 构建NTRU格用于密钥恢复。 h = 公钥多项式(模q) q = 模数 N = 维度 """ # NTRU格: # | qI 0 | # | H I | # 其中H是h的循环矩阵
H = matrix(ZZ, N, N)
for i in range(N):
    for j in range(N):
        H[i, j] = h[(j - i) % N]

M = block_matrix([
    [q * identity_matrix(N), zero_matrix(N)],
    [H, identity_matrix(N)]
])

L = M.LLL()

# 规约基中的短向量 = (f, g) 私钥
for row in L:
    f = vector(row[:N])
    g = vector(row[N:])
    if f.norm() < q and g.norm() < q:
        return f, g

return None

---

8. CONSTRUCTING ATTACK LATTICES — METHODOLOGY

8. 攻击格构建方法

8.1 General Recipe

8.1 通用流程

1. Express the cryptographic problem as:
   "Find small x such that f(x) ≡ 0 (mod N)"
   or "Find x close to target t in some lattice L"

2. Choose lattice type:
   ├─ Polynomial lattice → Coppersmith-style
   ├─ Modular lattice → HNP-style CVP
   └─ Knapsack lattice → subset sum / CJLOSS

3. Determine dimensions:
   └─ More dimensions = better approximation but slower

4. Set scaling factors:
   └─ Balance the rows so short vector has roughly equal entries
   └─ Common: multiply by N/X where X is the root bound

5. Apply reduction:
   ├─ LLL first (fast, usually sufficient)
   └─ BKZ if LLL fails (increase block size: 20, 30, 40)

6. Extract solution:
   └─ Check reduced basis rows for valid solutions
1. 将密码问题转化为以下形式:
   "寻找小x满足f(x) ≡ 0 (mod N)"
   或 "在格L中寻找接近目标t的x"

2. 选择格类型:
   ├─ 多项式格 → Coppersmith风格攻击
   ├─ 模块化格 → HNP风格CVP
   └─ 背包格 → 子集和 / CJLOSS

3. 确定维度:
   └─ 维度越高近似效果越好,但速度越慢

4. 设置缩放因子:
   └─ 平衡行向量,使短向量的元素大小大致相当
   └─ 通用方案:乘以N/X,其中X是根边界

5. 应用规约:
   ├─ 优先使用LLL(速度快,通常足够)
   └─ 若LLL失败则使用BKZ(逐步增加块大小:20, 30, 40)

6. 提取解:
   └─ 检查规约基的行是否为有效解

8.2 Embedding Technique (CVP → SVP)

8.2 嵌入技术(CVP → SVP)

Transform CVP into SVP by embedding the target into the lattice:
python
undefined
通过将目标向量嵌入格中,将CVP转化为SVP问题:
python
undefined

SageMath

SageMath

def cvp_to_svp(basis_matrix, target, scale=1): """Convert CVP to SVP via Kannan's embedding.""" n = basis_matrix.nrows() m = basis_matrix.ncols()
# Augment matrix
M = matrix(ZZ, n + 1, m + 1)
for i in range(n):
    for j in range(m):
        M[i, j] = basis_matrix[i, j]
    M[i, m] = 0

for j in range(m):
    M[n, j] = target[j]
M[n, m] = scale  # scaling factor (try 1, then adjust)

L = M.LLL()

# Look for row with last entry = ±scale
for row in L:
    if abs(row[m]) == scale:
        return vector(target) - vector(row[:m]) * (row[m] // abs(row[m]))

return None
undefined
def cvp_to_svp(basis_matrix, target, scale=1): """通过Kannan嵌入将CVP转化为SVP。""" n = basis_matrix.nrows() m = basis_matrix.ncols()
# 扩展矩阵
M = matrix(ZZ, n + 1, m + 1)
for i in range(n):
    for j in range(m):
        M[i, j] = basis_matrix[i, j]
    M[i, m] = 0

for j in range(m):
    M[n, j] = target[j]
M[n, m] = scale  # 缩放因子(先尝试1,再调整)

L = M.LLL()

# 查找最后一个元素为±scale的行
for row in L:
    if abs(row[m]) == scale:
        return vector(target) - vector(row[:m]) * (row[m] // abs(row[m]))

return None
undefined

8.3 Dimension Selection Guide

8.3 维度选择指南

ProblemTypical DimensionNotes
Coppersmith univariate (degree d)d × m where m ≈ 1/εLarger m = smaller root bound
HNP with n signaturesn + 2n ≥ known_bits_ratio × q_bits
Knapsack with n weightsn + 1 or n + 2Depends on density
LCG with n outputsn + 1More outputs = easier
Boneh-Durfee(m+1)(m+2)/2m = parameter depth

问题典型维度说明
单变量Coppersmith(次数d)d × m,其中m ≈ 1/εm越大根边界越小
含n个签名的HNPn + 2n ≥ 已知比特比例 × q的比特数
含n个权重的背包问题n + 1 或 n + 2取决于密度
含n个输出的LCGn + 1输出越多越容易破解
Boneh-Durfee(m+1)(m+2)/2m是参数深度

9. DECISION TREE

9. 决策树

Lattice approach needed — which construction?
├─ RSA-related?
│  ├─ Small unknown part of message → Coppersmith univariate
│  │  └─ Check: unknown_bits < n_bits / e
│  ├─ Partial factor knowledge → Coppersmith mod p
│  │  └─ Use beta=0.5, X=2^unknown_bits
│  ├─ Small private exponent d → Boneh-Durfee
│  │  └─ Check: d < N^0.292
│  └─ Multiple related equations → multivariate Coppersmith
├─ DSA/ECDSA-related?
│  ├─ Reused nonce → direct algebraic recovery (no lattice needed)
│  ├─ Partial nonce leakage → HNP → CVP lattice
│  │  └─ Need enough signatures: n ≥ q_bits / leaked_bits
│  └─ Nonce bias → statistical HNP → larger lattice
├─ Knapsack / subset sum?
│  ├─ Low density (d < 0.9408) → CJLOSS lattice attack
│  ├─ High density → lattice attack unlikely to work
│  └─ Super-increasing → greedy algorithm (no lattice needed)
├─ LCG / PRNG?
│  ├─ Full outputs known → algebraic recovery (no lattice)
│  ├─ Truncated outputs → CVP on recurrence lattice
│  └─ Unknown modulus → use GCD of output differences
├─ NTRU?
│  └─ Build circulant lattice → LLL/BKZ for short key vector
└─ Custom problem?
   ├─ Express as "find small root of polynomial mod N" → Coppersmith
   ├─ Express as "find lattice point close to target" → CVP
   ├─ Express as "find short vector in lattice" → SVP / LLL
   └─ If none fit → probably not a lattice problem

需要使用格方法——选择哪种构造?
├─ 与RSA相关?
│  ├─ 消息存在小的未知部分 → 单变量Coppersmith
│  │  └─ 检查:unknown_bits < n_bits / e
│  ├─ 部分因子信息已知 → 模p的Coppersmith
│  │  └─ 使用beta=0.5,X=2^未知比特数
│  ├─ 私钥指数d很小 → Boneh-Durfee
│  │  └─ 检查:d < N^0.292
│  └─ 多个相关等式 → 多变量Coppersmith
├─ 与DSA/ECDSA相关?
│  ├─ 随机数重用 → 直接代数恢复(无需格)
│  ├─ 部分随机数泄露 → HNP → CVP格
│  │  └─ 需要足够签名:n ≥ q比特数 / 泄露比特数
│  └─ 随机数偏差 → 统计HNP → 更大的格
├─ 背包/子集和问题?
│  ├─ 低密度(d < 0.9408) → CJLOSS格攻击
│  ├─ 高密度 → 格攻击大概率无效
│  └─ 超递增序列 → 贪心算法(无需格)
├─ LCG/PRNG问题?
│  ├─ 完整输出已知 → 代数恢复(无需格)
│  ├─ 截断输出 → 递推格上的CVP
│  └─ 模数未知 → 对输出差值求GCD
├─ NTRU问题?
│  └─ 构建循环格 → LLL/BKZ寻找短密钥向量
└─ 自定义问题?
   ├─ 可表示为「寻找多项式模N的小根」 → Coppersmith
   ├─ 可表示为「寻找接近目标的格点」 → CVP
   ├─ 可表示为「寻找格中的短向量」 → SVP / LLL
   └─ 都不满足 → 大概率不是格相关问题

10. COMMON PITFALLS

10. 常见陷阱

PitfallSymptomFix
Root bound too large
small_roots()
returns empty
Reduce X, increase epsilon, verify bound satisfies Coppersmith criterion
Wrong scalingLLL finds irrelevant short vectorScale columns so target vector has balanced entries
Insufficient dimensionSolution not in reduced basisIncrease m parameter (more shift polynomials)
Wrong betaCoppersmith doesn't find factorbeta=0.5 for half-size factor, beta=1.0 for full modulus
Too few signatures (HNP)Lattice attack failsCollect more signatures with nonce bias
BKZ block size too smallSolution not short enoughIncrease block size (try 25, 30, 40)
Integer overflowSageMath crashesUse ZZ ring explicitly, avoid mixing QQ and ZZ
陷阱表现修复方案
根边界过大
small_roots()
返回空列表
减小X,增大epsilon,验证边界满足Coppersmith条件
缩放错误LLL返回无关的短向量缩放列向量,使目标向量的元素大小均衡
维度不足规约基中不存在解增大m参数(添加更多平移多项式)
beta参数错误Coppersmith找不到因子半长因子用beta=0.5,全模数用beta=1.0
签名数量不足(HNP)格攻击失败收集更多存在随机数偏差的签名
BKZ块大小过小解的长度不够短增大块大小(尝试25、30、40)
整数溢出SageMath崩溃显式使用ZZ环,避免混合QQ和ZZ类型