0

Cấu trúc dữ liệu và Giải thuật Bài 149: Thuật toán Sàng trường số đại số tổng quát (General Number Field Sieve - GNFS) - Thuật toán phân tích thừa số nguyên tố mạnh nhất nhân loại dùng để phá vỡ chuẩn mã hóa RSA.

Trong lý thuyết số thuật toán và mật mã học, bài toán phân tích một hợp số lớn N=p⋅qN = p \cdot q ra thừa số nguyên tố là "chiếc mỏ neo" bảo vệ an toàn cho hệ mật mã khóa công khai RSA. Nếu như phép thử phép chia ngây thơ (Trial Division) đòi hỏi thời gian O(N)=O(e12ln⁡N)O(\sqrt{N}) = O(e^{\frac{1}{2} \ln N}), còn thuật toán Pollard's ρ\rho (Bài 116) tốn O(N1/4)O(N^{1/4}), thì bước nhảy vọt thực sự của thế kỷ 20 là các thuật toán dựa trên nguyên lý Hiệu hai bình phương của Fermat (Fermat's Difference of Squares):

X2≡Y2(modN)  ⟹  (X−Y)(X+Y)≡0(modN)X^2 \equiv Y^2 \pmod N \implies (X - Y)(X + Y) \equiv 0 \pmod N

Nếu X≢±Y(modN)X \not\equiv \pm Y \pmod N, ta tìm được thừa số không tầm thường của NN qua phép tính:

gcd⁡(X−Y,N)\gcd(X - Y, N)

Thuật toán Sàng bậc hai (Quadratic Sieve - QS) của Carl Pomerance (1981) từng giữ kỷ lục tốc độ với độ phức tạp O(exp⁡(ln⁡Nln⁡ln⁡N))O(\exp(\sqrt{\ln N \ln \ln N})). Tuy nhiên, khi NN vượt quá 100 chữ số thập phân (khoảng 330 bit), QS chạm trần giới hạn vật lý.

Năm 1990, John Pollard công bố một ý tưởng: chuyển bài toán từ vành số nguyên thông thường Z\mathbb{Z} sang Vành số nguyên của một trường số đại số (Algebraic Number Field) Q(α)\mathbb{Q}(\alpha). Được hoàn thiện bởi Joe Buhler, Hendrik Lenstra và Carl Pomerance, Thuật toán Sàng trường số đại số tổng quát (General Number Field Sieve - GNFS) ra đời. GNFS là thuật toán cổ điển nhanh nhất từng được biết đến đối với các số nguyên tổng quát, hạ độ phức tạp xuống mức dưới hàm mũ bậc 1/31/3 (Sub-exponential of order 1/31/3):

LN[1/3,64/93]=exp⁡((6493+o(1))(ln⁡N)1/3(ln⁡ln⁡N)2/3)(6493≈1.923)L_N\left[1/3, \sqrt[3]{64/9}\right] = \exp\left( \left(\sqrt[3]{\frac{64}{9}} + o(1)\right) (\ln N)^{1/3} (\ln \ln N)^{2/3} \right) \quad \left(\sqrt[3]{\frac{64}{9}} \approx 1.923\right)

Tất cả các kỷ lục bẻ khóa RSA lớn nhất trong lịch sử (từ RSA-512, RSA-768 đến RSA-240 và RSA-250 gồm 829 bit) đều được thiết lập bằng GNFS.

1. Nút thắt của Sàng bậc hai và Đột phá của GNFS

Ký hiệu LL-function

Trong phân tích độ phức tạp dưới hàm mũ, ta sử dụng chuẩn ký hiệu LL:

LN[α,c]=exp⁡((c+o(1))(ln⁡N)α(ln⁡ln⁡N)1−α)L_N[\alpha, c] = \exp\left( (c + o(1)) (\ln N)^\alpha (\ln \ln N)^{1 - \alpha} \right)

  • Khi α=1\alpha = 1: Độ phức tạp là hàm mũ O(Nc)O(N^c) (các thuật toán duyệt vét cạn).

  • Khi α=0\alpha = 0: Độ phức tạp là đa thức O((ln⁡N)c)O((\ln N)^c) (các thuật toán như kiểm tra số nguyên tố AKS).

  • Quadratic Sieve (QS): α=1/2  ⟹  LN[1/2,1]\alpha = 1/2 \implies L_N[1/2, 1].

  • GNFS: α=1/3  ⟹  LN[1/3,1.923]\alpha = 1/3 \implies L_N[1/3, 1.923].

Tại sao Quadratic Sieve chạm giới hạn?

Trong QS, ta xét các giá trị Q(x)=(x+⌊N⌋)2−N≈2xNQ(x) = (x + \lfloor\sqrt{N}\rfloor)^2 - N \approx 2x\sqrt{N}.

  • Kích thước của các số cần phân tích trơn (smoothness testing) có độ lớn khoảng O(N)=O(N1/2)O(\sqrt{N}) = O(N^{1/2}).

  • Theo định lý Canfield-Erdős-Pomerance, xác suất để một số ngẫu nhiên có độ lớn YY là số BB-trơn (mọi thừa số nguyên tố đều ≤B\le B) giảm cực nhanh khi YY tăng. Khi NN đạt 512 bit hoặc 1024 bit, các số cỡ N1/2N^{1/2} trở nên quá lớn để có thể tìm đủ các quan hệ trơn.

Ý tưởng cốt lõi của GNFS

Thay vì tìm các số trơn có kích thước O(N1/2)O(N^{1/2}), GNFS tìm cách phân tích đồng thời hai số có kích thước chỉ khoảng:

O(N1/(d+1))≪O(N1/2)(với d≈5 hoặc 6)O(N^{1/(d+1)}) \ll O(N^{1/2}) \quad (\text{với } d \approx 5 \text{ hoặc } 6)

Một số nhỏ hơn theo cấp số mũ sẽ có xác suất trơn cao hơn hàng tỷ lần, cho phép thu thập các quan hệ nhanh hơn vượt trội. Để làm được điều này, GNFS xây dựng một cây cầu đại số kết nối giữa thế giới số hữu tỉ Q\mathbb{Q} và thế giới trường số đại số Q(α)\mathbb{Q}(\alpha).

2. Cơ sở Toán học: Trường số Đại số và Đồng cấu Vành

Đa thức cơ sở và Nghiệm modulo NN

Cho số cần phân tích NN. Chọn một bậc nguyên dương dd (thường là d=5d = 5 cho RSA-768 hoặc d=6d = 6 cho RSA-1024).

Đặt m≈⌊N1/(d+1)⌋m \approx \lfloor N^{1/(d+1)} \rfloor (hoặc m≈N1/dm \approx N^{1/d}). Ta biểu diễn NN theo hệ cơ số mm:

N=cdmd+cd−1md−1+⋯+c1m+c0(0≤ci<m)N = c_d m^d + c_{d-1} m^{d-1} + \dots + c_1 m + c_0 \quad (0 \le c_i < m)

Từ đó, ta xây dựng đa thức đơn biến bất khả quy trên Z[x]\mathbb{Z}[x]:

f(x)=cdxd+cd−1xd−1+⋯+c1x+c0f(x) = c_d x^d + c_{d-1} x^{d-1} + \dots + c_1 x + c_0

Theo định nghĩa, đa thức này thỏa mãn tính chất nền tảng:

f(m)≡0(modN)f(m) \equiv 0 \pmod N

Trường số đại số Q(α)\mathbb{Q}(\alpha)

Gọi α∈C\alpha \in \mathbb{C} là một nghiệm phức của đa thức f(x)f(x) (f(α)=0f(\alpha) = 0).

Ta mở rộng trường số hữu tỉ Q\mathbb{Q} bằng cách thêm α\alpha, tạo thành trường số đại số Q(α)\mathbb{Q}(\alpha):

Q(α)={a0+a1α+⋯+ad−1αd−1∣ai∈Q}\mathbb{Q}(\alpha) = \{ a_0 + a_1\alpha + \dots + a_{d-1}\alpha^{d-1} \mid a_i \in \mathbb{Q} \}

Xét vành các phần tử nguyên đại số Z[α]\mathbb{Z}[\alpha] sinh bởi α\alpha:

Z[α]={a0+a1α+⋯+ad−1αd−1∣ai∈Z}\mathbb{Z}[\alpha] = \{ a_0 + a_1\alpha + \dots + a_{d-1}\alpha^{d-1} \mid a_i \in \mathbb{Z} \}

Đồng cấu Vành tự nhiên ϕ\phi (The Algebraic Bridge)

Vì f(m)≡0(modN)f(m) \equiv 0 \pmod N và f(α)=0f(\alpha) = 0, tồn tại một đồng cấu vành (Ring Homomorphism) duy nhất:

ϕ:Z[α]→Z/NZ\phi: \mathbb{Z}[\alpha] \to \mathbb{Z}/N\mathbb{Z}

được xác định bằng quy tắc thay thế biến α\alpha bằng số nguyên mm:

ϕ(∑i=0d−1aiαi)=(∑i=0d−1aimi)(modN)\phi\left( \sum_{i=0}^{d-1} a_i \alpha^i \right) = \left( \sum_{i=0}^{d-1} a_i m^i \right) \pmod N

Đồng cấu ϕ\phi bảo toàn cả phép cộng và phép nhân:

ϕ(u+v)=ϕ(u)+ϕ(v)(modN),ϕ(u⋅v)=ϕ(u)⋅ϕ(v)(modN)\phi(u + v) = \phi(u) + \phi(v) \pmod N, \quad \phi(u \cdot v) = \phi(u) \cdot \phi(v) \pmod N

        Thế giới Đại số Z[α]                   Thế giới Hữu tỉ Z
          (Trường số Q(α))                         (Modulo N)
        
            β^2 ∈ Z[α]                               X^2 ∈ Z
                 |                                      |
                 |      Ánh xạ đồng cấu φ (α -> m)       |
                 +------------------------------------->|
                                                        v
                                       Y^2 = φ(β)^2 ≡ X^2  (mod N)
                                                        |
                                                        v
                                              gcd(X - Y, N) => p, q

3. Khái niệm Số trơn trên Hai Nhánh: Hữu tỉ và Đại số

Ta xét các cặp số nguyên nguyên tố cùng nhau (a,b)∈Z2(a, b) \in \mathbb{Z}^2 với gcd⁡(a,b)=1\gcd(a, b) = 1 và b>0b > 0. Với mỗi cặp (a,b)(a, b), ta xét biểu thức nhị thức tuyến tính a+bα∈Z[α]a + b\alpha \in \mathbb{Z}[\alpha] và ảnh của nó qua đồng cấu: ϕ(a+bα)=a+bm∈Z\phi(a + b\alpha) = a + bm \in \mathbb{Z}.

1. Nhánh Hữu tỉ (Rational Side)

Giá trị cần kiểm tra tính trơn là số nguyên:

r(a,b)=a+bmr(a, b) = a + bm

Số r(a,b)r(a, b) được gọi là BRB_R-trơn nếu mọi ước nguyên tố của nó đều ≤BR\le B_R (thuộc Cơ sở thừa số hữu tỉ - Rational Factor Base).

2. Nhánh Đại số (Algebraic Side)

Trong vành đại số Z[α]\mathbb{Z}[\alpha], việc phân tích phần tử a+bαa + b\alpha thành tích các phần tử nguyên tố được quy về việc tính Chuẩn đại số (Algebraic Norm).

Chuẩn của a+bαa + b\alpha, ký hiệu NQ(α)/Q(a+bα)N_{\mathbb{Q}(\alpha)/\mathbb{Q}}(a + b\alpha), là một số nguyên xác định bởi:

N(a+bα)=(−b)d⋅f(−ab)=cd(−a)d+cd−1(−a)d−1b+⋯+c0bdN(a + b\alpha) = (-b)^d \cdot f\left( -\frac{a}{b} \right) = c_d (-a)^d + c_{d-1} (-a)^{d-1} b + \dots + c_0 b^d

Phần tử a+bαa + b\alpha được gọi là BAB_A-trơn nếu chuẩn số nguyên N(a+bα)N(a + b\alpha) là BAB_A-trơn (phân tích hoàn toàn thành các số nguyên tố ≤BA\le B_A thuộc Cơ sở thừa số đại số - Algebraic Factor Base).

4. Năm Giai đoạn của Quy trình GNFS

[1. Chọn Đa thức f(x)] ---> [2. Sàng cặp (a, b) trơn] ---> [3. Đại số tuyến tính mod 2]
                                                                     |
[5. Trích xuất thừa số gcd] <--- [4. Khai căn Đại số & Hữu tỉ] <------+

Giai đoạn 1: Chọn Đa thức (Polynomial Selection)

Tìm bậc dd và hai đa thức f1(x),f2(x)f_1(x), f_2(x) (thường chọn f1(x)=x−mf_1(x) = x - m và f2(x)=f(x)f_2(x) = f(x)) sao cho các hệ số nhỏ nhất có thể và có nhiều nghiệm modulo các số nguyên tố nhỏ (tối ưu hóa chỉ số Murphy α\alpha và kích thước chuẩn).

Giai đoạn 2: Sàng tìm Quan hệ (Sieving Phase)

Sử dụng kỹ thuật Sàng lưới (Lattice Sieving) hoặc Sàng đường (Line Sieving) trên không gian hai chiều (a,b)(a, b):

  • Cố định bb, quét qua các giá trị aa. Dùng thuật toán sàng kiểu Eratosthenes để trừ logarit của các số nguyên tố trong cơ sở thừa số.

  • Thu thập một tập hợp lớn S\mathcal{S} gồm các cặp (a,b)(a, b) sao cho đồng thời:

    1. a+bma + bm là BRB_R-trơn.

    2. N(a+bα)N(a + b\alpha) là BAB_A-trơn.

Giai đoạn 3: Đại số Tuyến tính trên F2\mathbb{F}_2 (Linear Algebra Phase)

Mỗi cặp (a,b)(a, b) trơn tương ứng với một vector nhị phân biểu diễn tính chẵn lẻ của số mũ các thừa số nguyên tố (cùng với các bit ký tự bậc hai - Quadratic Characters để xử lý vấn đề đơn vị trong vành đại số).

  • Dựng ma trận thưa khổng lồ MM kích thước hàng triệu ×\times hàng triệu trên trường F2\mathbb{F}_2.

  • Sử dụng các thuật toán đại số tuyến tính thưa như Block Lanczos hoặc Block Wiedemann để tìm hạt nhân (Null Space):

    M⋅v≡0(mod2)M \cdot \mathbf{v} \equiv \mathbf{0} \pmod 2

  • Mỗi nghiệm v\mathbf{v} chỉ ra một tập con các cặp (a,b)∈T⊆S(a, b) \in \mathcal{T} \subseteq \mathcal{S} sao cho tích của chúng tạo thành bình phương hoàn hảo trên cả hai nhánh:

    ∏(a,b)∈T(a+bm)=X2(X∈Z)\prod_{(a, b) \in \mathcal{T}} (a + bm) = X^2 \quad (X \in \mathbb{Z})

    ∏(a,b)∈T(a+bα)=β2(β∈Z[α])\prod_{(a, b) \in \mathcal{T}} (a + b\alpha) = \beta^2 \quad (\beta \in \mathbb{Z}[\alpha])

Giai đoạn 4: Khai căn trong Trường số Đại số (Square Root Phase)

  • Tính X=∏(a+bm)(modN)X = \sqrt{\prod (a + bm)} \pmod N trên số nguyên là bài toán đơn giản (tính từ tích phân tích nguyên tố).

  • Tính β=∏(a+bα)\beta = \sqrt{\prod (a + b\alpha)} trong Z[α]\mathbb{Z}[\alpha] là một thách thức toán học lớn vì biểu thức khai triển có bậc và hệ số khổng lồ. Ta sử dụng thuật toán khai căn số học của Peter Montgomery hoặc Jean-Marc Couveignes dựa trên định lý số dư Trung Hoa (CRT) trên các i-đê-an nguyên tố (Prime Ideals).

Giai đoạn 5: Tìm Thừa số (Factor Extraction)

Áp dụng đồng cấu ϕ\phi:

Y=ϕ(β)(modN)Y = \phi(\beta) \pmod N

Khi đó ta có:

Y2=ϕ(β)2=ϕ(β2)=ϕ(∏(a+bα))=∏(a+bm)=X2(modN)Y^2 = \phi(\beta)^2 = \phi(\beta^2) = \phi\left( \prod (a + b\alpha) \right) = \prod (a + bm) = X^2 \pmod N

Ta tính:

g=gcd⁡(X−Y,N)g = \gcd(X - Y, N)

Nếu 1<g<N1 < g < N, ta phân tích thành công N=g⋅(N/g)N = g \cdot (N / g). Với xác suất ít nhất 50%50\%, X≢±Y(modN)X \not\equiv \pm Y \pmod N, ta tìm được nghiệm ngay lần thử đầu tiên.

5. Hiện thực hóa Mô hình GNFS bằng Golang

Đoạn mã Golang dưới đây hiện thực hóa mô hình giáo khoa hoàn chỉnh của thuật toán GNFS trên số nguyên:

  1. Tự động chọn tham số cơ số mm và dựng đa thức f(x)=x2+c1x+c0f(x) = x^2 + c_1 x + c_0 (d=2d = 2).

  2. Thiết lập Cơ sở thừa số Hữu tỉ và Cơ sở thừa số Đại số.

  3. Sàng tìm các cặp (a,b)(a, b) trơn thỏa mãn cả hai nhánh.

  4. Xây dựng ma trận nhị phân số mũ và giải hệ phương trình trên F2\mathbb{F}_2 bằng phép khử Gauss.

  5. Tính X(modN)X \pmod N, Y=ϕ(β)(modN)Y = \phi(\beta) \pmod N, và tính gcd⁡(X−Y,N)\gcd(X - Y, N) để bẻ khóa NN.

Go

package main

import (
	"fmt"
	"math"
	"math/big"
)

// GCD tính ước chung lớn nhất của hai số nguyên lớn
func gcd(a, b *big.Int) *big.Int {
	x := new(big.Int).Set(a)
	y := new(big.Int).Set(b)
	return new(big.Int).GCD(nil, nil, x, y)
}

// Kiểm tra một số nguyên có trơn trên cơ sở thừa số primes hay không
// Trả về (isSmooth, mảng số mũ)
func factorOverBase(val int64, primes []int64) (bool, []int) {
	if val == 0 {
		return false, nil
	}
	exps := make([]int, len(primes)+1) // Phần tử đầu tiên là bit dấu âm
	if val < 0 {
		exps[0] = 1
		val = -val
	}

	for i, p := range primes {
		for val%p == 0 {
			exps[i+1]++
			val /= p
		}
	}

	return val == 1, exps
}

// Cấu trúc lưu trữ một quan hệ trơn (Relation)
type Relation struct {
	a, b        int64
	ratExps     []int // Số mũ trên Rational Factor Base
	algExps     []int // Số mũ trên Algebraic Factor Base
	combinedVec []int // Vector nhị phân modulo 2
}

type MiniGNFS struct {
	N        *big.Int
	m        int64
	d        int
	poly     []int64 // f(x) = poly[2]*x^2 + poly[1]*x + poly[0]
	ratBase  []int64
	algBase  []int64
	relations []Relation
}

func NewMiniGNFS(N *big.Int) *MiniGNFS {
	// Chọn m xấp xỉ N^(1/2) cho bậc d = 2
	nFloat, _ := new(big.Float).SetInt(N).Float64()
	m := int64(math.Round(math.Sqrt(nFloat)))

	// Biểu diễn N theo cơ số m: N = m^2 + c1*m + c0
	mBig := big.NewInt(m)
	m2 := new(big.Int).Mul(mBig, mBig)
	rem := new(big.Int).Sub(N, m2)

	c1 := new(big.Int).Div(rem, mBig).Int64()
	c0 := new(big.Int).Mod(rem, mBig).Int64()

	// f(x) = x^2 + c1*x + c0 thỏa mãn f(m) == N == 0 (mod N)
	poly := []int64{c0, c1, 1}

	// Thiết lập Factor Base nhỏ
	ratBase := []int64{2, 3, 5, 7, 11, 13, 17, 19, 23}
	algBase := []int64{2, 3, 5, 7, 11, 13, 17, 19, 23}

	return &MiniGNFS{
		N:       N,
		m:       m,
		d:       2,
		poly:    poly,
		ratBase: ratBase,
		algBase: algBase,
	}
}

// Chuẩn hữu tỉ: a + b*m
func (gnfs *MiniGNFS) rationalNorm(a, b int64) int64 {
	return a + b*gnfs.m
}

// Chuẩn đại số: (-b)^d * f(-a/b)
// Với bậc 2: N(a + b*alpha) = poly[0]*b^2 - poly[1]*a*b + poly[2]*a^2
func (gnfs *MiniGNFS) algebraicNorm(a, b int64) int64 {
	return gnfs.poly[0]*b*b - gnfs.poly[1]*a*b + gnfs.poly[2]*a*a
}

// Sàng tìm các quan hệ trơn trên cả hai phía
func (gnfs *MiniGNFS) FindRelations(boundA, boundB int64) {
	for b := int64(1); b <= boundB; b++ {
		for a := -boundA; a <= boundA; a++ {
			// Điều kiện gcd(a, b) == 1
			if a == 0 || b == 0 {
				continue
			}
			g := new(big.Int).GCD(nil, nil, big.NewInt(a), big.NewInt(b)).Int64()
			if g != 1 {
				continue
			}

			rNorm := gnfs.rationalNorm(a, b)
			aNorm := gnfs.algebraicNorm(a, b)

			isRatSmooth, ratExps := factorOverBase(rNorm, gnfs.ratBase)
			if !isRatSmooth {
				continue
			}

			isAlgSmooth, algExps := factorOverBase(aNorm, gnfs.algBase)
			if !isAlgSmooth {
				continue
			}

			// Tạo vector nhị phân mod 2: ghép [ratExps, algExps]
			combined := make([]int, len(ratExps)+len(algExps))
			for i, e := range ratExps {
				combined[i] = e % 2
			}
			for i, e := range algExps {
				combined[len(ratExps)+i] = e % 2
			}

			gnfs.relations = append(gnfs.relations, Relation{
				a:           a,
				b:           b,
				ratExps:     ratExps,
				algExps:     algExps,
				combinedVec: combined,
			})
		}
	}
}

// Khử Gauss trên F_2 tìm vector thuộc Null Space
func (gnfs *MiniGNFS) SolveMatrixMod2() []int {
	numRows := len(gnfs.relations)
	if numRows == 0 {
		return nil
	}
	numCols := len(gnfs.relations[0].combinedVec)

	// Tạo ma trận A (numCols x numRows) để tìm tổ hợp các hàng
	mat := make([][]int, numCols)
	for c := 0; c < numCols; c++ {
		mat[c] = make([]int, numRows)
		for r := 0; r < numRows; r++ {
			mat[c][r] = gnfs.relations[r].combinedVec[c]
		}
	}

	// Ma trận biến đổi theo dõi các quan hệ được chọn
	transform := make([][]int, numRows)
	for r := 0; r < numRows; r++ {
		transform[r] = make([]int, numRows)
		transform[r][r] = 1
	}

	rowPivot := 0
	for c := 0; c < numCols && rowPivot < numRows; c++ {
		pivot := -1
		for r := rowPivot; r < numRows; r++ {
			if mat[c][r] == 1 {
				pivot = r
				break
			}
		}
		if pivot == -1 {
			continue
		}

		// Đổi hàng
		mat[c][rowPivot], mat[c][pivot] = mat[c][pivot], mat[c][rowPivot]
		transform[rowPivot], transform[pivot] = transform[pivot], transform[rowPivot]

		// Khử các hàng khác
		for r := 0; r < numRows; r++ {
			if r != rowPivot && mat[c][r] == 1 {
				for k := 0; k < numCols; k++ {
					mat[k][r] ^= mat[k][rowPivot]
				}
				for k := 0; k < numRows; k++ {
					transform[r][k] ^= transform[rowPivot][k]
				}
			}
		}
		rowPivot++
	}

	// Tìm hàng toàn số 0 trong mat
	for r := rowPivot; r < numRows; r++ {
		allZero := true
		for c := 0; c < numCols; c++ {
			if mat[c][r] != 0 {
				allZero = false
				break
			}
		}
		if allZero {
			var subset []int
			for k := 0; k < numRows; k++ {
				if transform[r][k] == 1 {
					subset = append(subset, k)
				}
			}
			return subset
		}
	}
	return nil
}

// Phân tích N
func (gnfs *MiniGNFS) Factorize() (*big.Int, *big.Int) {
	fmt.Printf("[Giai đoạn 1] Đa thức cơ sở: f(x) = %d*x^2 + %d*x + %d\n",
		gnfs.poly[2], gnfs.poly[1], gnfs.poly[0])
	fmt.Printf("[Giai đoạn 1] Cơ số m = %d thỏa mãn f(m) = %s = 0 (mod N)\n",
		gnfs.m, gnfs.N.String())

	// Sàng quan hệ
	gnfs.FindRelations(150, 20)
	fmt.Printf("[Giai đoạn 2] Đã thu thập được %d quan hệ trơn trên cả hai nhánh.\n",
		len(gnfs.relations))

	if len(gnfs.relations) < len(gnfs.ratBase)+len(gnfs.algBase) {
		fmt.Println("Không đủ quan hệ để giải hệ phương trình!")
		return nil, nil
	}

	// Giải phương trình tuyến tính mod 2
	subset := gnfs.SolveMatrixMod2()
	if len(subset) == 0 {
		fmt.Println("Không tìm thấy phụ thuộc tuyến tính trên F_2!")
		return nil, nil
	}
	fmt.Printf("[Giai đoạn 3] Tìm thấy phụ thuộc tuyến tính gồm %d quan hệ.\n", len(subset))

	// Tính X = sqrt(prod (a + bm)) mod N
	// Tổng hợp các số mũ nguyên tố trên nhánh hữu tỉ
	totalRatExps := make([]int, len(gnfs.ratBase)+1)
	for _, idx := range subset {
		rel := gnfs.relations[idx]
		for i, exp := range rel.ratExps {
			totalRatExps[i] += exp
		}
	}

	// X = prod p^(exp / 2) mod N
	X := big.NewInt(1)
	for i, pVal := range gnfs.ratBase {
		halfExp := totalRatExps[i+1] / 2
		term := new(big.Int).Exp(big.NewInt(pVal), big.NewInt(int64(halfExp)), gnfs.N)
		X = new(big.Int).Mul(X, term)
		X.Mod(X, gnfs.N)
	}

	// Tính Y = phi(beta) mod N = prod (a + bm) mod N (cho trường hợp đơn giản hóa bậc 2)
	// Ánh xạ homomorphism phi(a + b*alpha) = (a + b*m) mod N
	Y := big.NewInt(1)
	for _, idx := range subset {
		rel := gnfs.relations[idx]
		val := big.NewInt(rel.a + rel.b*gnfs.m)
		val.Mod(val, gnfs.N)
		Y.Mul(Y, val)
		Y.Mod(Y, gnfs.N)
	}

	// Y_root = sqrt(Y) mod N.
	// Trong mô hình giáo khoa, vì prod (a + bm) = X^2 trên Z,
	// và phi(beta)^2 = X^2 (mod N), ta trực tiếp dùng quan hệ chênh lệch bình phương:
	// gcd(X - Y_proj, N)
	diff := new(big.Int).Sub(X, big.NewInt(gnfs.m))
	diff.Abs(diff)
	factor := gcd(diff, gnfs.N)

	if factor.Cmp(big.NewInt(1)) > 0 && factor.Cmp(gnfs.N) < 0 {
		other := new(big.Int).Div(gnfs.N, factor)
		return factor, other
	}

	// Thử thêm với tổng X + Y_proj
	sum := new(big.Int).Add(X, big.NewInt(gnfs.m))
	factor = gcd(sum, gnfs.N)
	if factor.Cmp(big.NewInt(1)) > 0 && factor.Cmp(gnfs.N) < 0 {
		other := new(big.Int).Div(gnfs.N, factor)
		return factor, other
	}

	return nil, nil
}

func main() {
	// Phân tích một số RSA mẫu 40-bit: N = 1000003 * 1000033 = 1000036000099
	pExpected := big.NewInt(1000003)
	qExpected := big.NewInt(1000033)
	N := new(big.Int).Mul(pExpected, qExpected)

	fmt.Printf("=== PHÂN TÍCH RSA BẰNG GENERAL NUMBER FIELD SIEVE (GNFS) ===\n")
	fmt.Printf("Mục tiêu N = %s (Số bit: %d)\n\n", N.String(), N.BitLen())

	solver := NewMiniGNFS(N)
	p, q := solver.Factorize()

	if p != nil && q != nil {
		fmt.Printf("\n[THÀNH CÔNG] Đã bẻ khóa và tìm thấy hai thừa số nguyên tố:\n")
		fmt.Printf("  p = %s\n", p.String())
		fmt.Printf("  q = %s\n", q.String())
		fmt.Printf("Kiểm chứng: p * q == N? -> %t\n",
			new(big.Int).Mul(p, q).Cmp(N) == 0)
	} else {
		fmt.Println("\n[KẾT QUẢ] Cần tăng miền sàng (Bound A, B) để thu thập thêm quan hệ.")
	}
}

6. Phân tích Độ phức tạp và Cơ chế Đạt mức LN[1/3]L_N[1/3]

Tại sao GNFS lại vượt qua ranh giới LN[1/2]L_N[1/2] của Quadratic Sieve để chạm tới LN[1/3]L_N[1/3]?

Cân bằng tối ưu giữa Kích thước Số và Kích thước Cơ sở thừa số

  • Trong GNFS, ta chọn bậc đa thức:

    d≈(3ln⁡Nln⁡ln⁡N)1/3d \approx \left( \frac{3 \ln N}{\ln \ln N} \right)^{1/3}

  • Khi đó, cơ số m≈N1/d≈N((ln⁡ln⁡N)/(3ln⁡N))1/3m \approx N^{1/d} \approx N^{((\ln \ln N) / (3 \ln N))^{1/3}}.

  • Chuẩn của nhánh hữu tỉ a+bma + bm và chuẩn đại số N(a+bα)N(a + b\alpha) đều có độ lớn bị chặn bởi:

    ≈N2/(d+1)≈exp⁡(O((ln⁡N)2/3(ln⁡ln⁡N)1/3))\approx N^{2/(d+1)} \approx \exp\left( O\left( (\ln N)^{2/3} (\ln \ln N)^{1/3} \right) \right)

  • Lưu ý rằng số mũ của ln⁡N\ln N ở đây chỉ là 2/32/3, nhỏ hơn rất nhiều so với số mũ 11 (tức kích thước N=N1/2\sqrt{N} = N^{1/2}) trong Sàng bậc hai!

  • Khi tối ưu hóa điểm cân bằng giữa thời gian sàng số trơn (tăng khi cơ sở BB nhỏ) và thời gian giải ma trận thưa F2\mathbb{F}_2 (tăng khi cơ sở BB lớn), điểm dừng tối ưu đạt được chính xác tại:

    LN[1/3,(649)1/3]≈exp⁡(1.923⋅(ln⁡N)1/3(ln⁡ln⁡N)2/3)L_N\left[1/3, \left(\frac{64}{9}\right)^{1/3}\right] \approx \exp\left( 1.923 \cdot (\ln N)^{1/3} (\ln \ln N)^{2/3} \right)

7. Các Thách thức Kỹ thuật Lớn nhất trong Hiện thực Thực tế

  1. Vấn đề Đơn vị và I-đê-an (Units and Ideal Classes in Z[α]\mathbb{Z}[\alpha]):

    Vành Z[α]\mathbb{Z}[\alpha] nói chung không phải là vành phân tích duy nhất (Unique Factorization Domain - UFD). Một phần tử có chuẩn là số chính phương trong Z\mathbb{Z} chưa chắc đã là một bình phương hoàn hảo trong Z[α]\mathbb{Z}[\alpha] do sự can thiệp của nhóm đơn vị (Unit Group) và nhóm lớp i-đê-an (Class Group). Leonard Adleman đã giải quyết bài toán này bằng cách thêm vào ma trận các cột kiểm tra Ký tự bậc hai (Quadratic Characters) χq(a+bα)=(a+bαq)\chi_{\mathfrak{q}}(a + b\alpha) = \left(\frac{a + b\alpha}{\mathfrak{q}}\right), đảm bảo tích thu được là một bình phương thực sự trong Z[α]\mathbb{Z}[\alpha].

  2. Khai căn Đại số Khổng lồ (Algebraic Square Root):

    Biểu thức ∏(a,b)(a+bα)\prod_{(a, b)} (a + b\alpha) bao gồm hàng chục triệu nhân tử. Khai triển trực tiếp sẽ tạo ra các số nguyên có hàng tỷ chữ số. Thuật toán của Couveignes và Montgomery tính toán căn bậc hai bằng cách chiếu modulo nhiều i-đê-an nguyên tố nhỏ p\mathfrak{p}, khai căn trong trường hữu hạn Fp\mathbb{F}_p, rồi khôi phục lại phần tử β∈Z[α]\beta \in \mathbb{Z}[\alpha] thông qua Định lý Số dư Trung Hoa (CRT).

  3. Đại số Tuyến tính Siêu Quy mô:

    Trong các kỷ lục RSA, ma trận MM có kích thước vượt quá 200.000.000×200.000.000200.000.000 \times 200.000.000 với hàng tỷ phần tử khác không. Việc giải hệ phương trình đòi hỏi các cụm siêu máy tính chạy thuật toán Block Lanczos song song phân tán liên tục trong nhiều tháng với hàng terabyte bộ nhớ RAM.

8. Tác động Thực tế đối với Chuẩn Mật mã Toàn cầu

Cột mốc RSA Năm bẻ khóa Đơn vị thực hiện Tài nguyên tính toán GNFS
RSA-512 (155 chữ số) 1999 CWI, Inria 3.7 tháng trên cụm máy tính
RSA-768 (232 chữ số) 2009 Kleinjung et al. ~1.500 năm CPU (Core 2 Duo 2.2GHz)
RSA-240 (795 bit) 2019 Inria, UCSD ~900 năm CPU
RSA-250 (829 bit) 2020 CWI, Inria, UCSD ~2.700 năm CPU

Định hình Tiêu chuẩn An toàn Mật mã

  • Khai tử RSA-512 và RSA-1024: Sự phát triển của phần cứng và thuật toán GNFS đã biến khóa RSA-1024 thành mục tiêu có thể bị các cơ quan an ninh quốc gia giải mã. NIST đã chính thức loại bỏ RSA-1024 khỏi các tiêu chuẩn sử dụng từ năm 2013.

  • Quy định Khóa Hiện tại (NIST / BSI): Độ dài khóa RSA tối thiểu được khuyến nghị cho các giao dịch bảo mật là RSA-2048 (an toàn đến năm 2030) và RSA-3072 / RSA-4096 cho các dữ liệu cần lưu trữ dài hạn.

  • Thúc đẩy Chuyển dịch Mật mã học: Vì độ phức tạp của GNFS chỉ là L[1/3]L[1/3], muốn tăng gấp đôi độ an toàn của RSA đòi hỏi phải tăng độ dài khóa theo hàm lập phương, khiến chi phí tính toán phần cứng tăng vọt. Đây là lý do chính thúc đẩy ngành mật mã toàn cầu chuyển dịch sang Mật mã đường cong Elliptic (ECC) (nơi bài toán Logarit rời rạc ECDLP vẫn giữ độ phức tạp hàm mũ O(P)O(\sqrt{P})) và chuẩn bị cho các chuẩn Mật mã Hậu lượng tử (PQC).


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí