从问题到解决:数学知识的产生过程
这份文档不是简单地告诉你"什么是椭圆曲线",而是:
✅ 展示问题 - 为什么古人需要解决这个问题 ✅ 推导过程 - 数学家们怎么一步步推导出来的 ✅ 失败的尝试 - 为什么早期方法不行 ✅ 历史背景 - 这些想法是在什么时代产生的 ✅ 相互联系 - 各个概念怎么串联起来的
场景:公元前 5000 年的美索不达米亚
一个牧羊人有 23 只羊要分给 5 个儿子。
每个儿子可以得:23 ÷ 5 = 4 只
剩余:3 只
他该怎么办?
- 选项A:3只羊拿去卖掉
- 选项B:一个儿子多给1只,另外两个也多给1只
- 选项C:杀掉剩余的3只?
这个问题很简单,但它衍生出了"余数"的概念。
关键洞察:任何数都可以表示为:
被除数 = 除数 × 商 + 余数
23 = 5 × 4 + 3
问题的升级
古埃及人发现了更有趣的事:
如果我每 7 天休息一次,在一个周期中,我的日期永远循环于 0-6。
这启发了一个想法:我们可以忽略"完整的周期",只看余数。
例子:星期计算
今天是星期二(第2天)
问:50天后是星期几?
古老方法:50 ÷ 7 = 7 个完整周 + 1 天
所以 50 天后是:星期三(第 2+1 = 3 天)
数学表示:
50 ≡ 1 (mod 7)
2 + 50 ≡ 2 + 1 ≡ 3 (mod 7)
为什么模运算这么有用?
-
简化计算:我们不需要处理无限大的数,只需处理有限的"余数集合"
-
循环结构:时钟、日历、季节都是循环的——它们本质上是模运算
-
加密直觉:如果我只告诉你 50 mod 7 = 1,你无法反推出 50(可能是 1, 8, 15, 22, 29...)
加法在模下保持
如果 a ≡ x (mod p) 且 b ≡ y (mod p)
那么 (a + b) ≡ (x + y) (mod p)
为什么?
a = kp + x (某个k倍的p加x)
b = lp + y (某个l倍的p加y)
a + b = (k+l)p + (x+y)
= (k+l)p + (x+y) mod p
"完整周期"被抵消了,只剩余数相加
乘法也保持
如果 a ≡ x (mod p) 且 b ≡ y (mod p)
那么 (a×b) ≡ (x×y) (mod p)
例子:
23 ≡ 3 (mod 10)
17 ≡ 7 (mod 10)
23 × 17 = 391
3 × 7 = 21 ≡ 1 (mod 10)
391 mod 10 = 1 ✓ 一致!
这为什么重要?
这意味着我们可以在 mod 的世界里做完整的算术,规则完全一样。这是解锁密码学的关键。
场景:古希腊,约公元前 300 年
欧几里得(Euclid)问了一个基础问题:
所有正整数都是怎么"组成"的?
发现:质数
2 = 只能是 2
3 = 只能是 3
4 = 2 × 2
5 = 只能是 5
6 = 2 × 3
7 = 只能是 7
8 = 2 × 2 × 2
...
定义:质数是大于 1 的自然数,只能被 1 和自己整除。
欧几里得定理(最伟大的数学定理之一):
质数有无穷多个。
证明思路:
假设质数只有有限个:p1, p2, p3, ..., pn
那么考虑数 N = (p1 × p2 × ... × pn) + 1
N 有什么性质?
- N 不能被 p1 整除(因为 p1 × 某个数 + 1)
- N 不能被 p2 整除
- ...
- N 不能被 pn 整除
那 N 要么本身是质数,要么被某个新的质数整除。
任何情况下,都存在之前列表中没有的质数!
矛盾!所以质数无穷多。
问题 1:因数分解困难性
知道两个质数很容易:
p = 13
q = 17
n = p × q = 221
但反过来困难得多:
n = 221
求因数分解... 是 13 × 17 吗? 11 × 20? ...
随着质数越来越大,反向计算变得不可能。
问题 2:模质数下的魔法性质
当模数 p 是质数时,有一些不可思议的性质:
在 mod p 的世界里(p 是质数)
对于任何 1 ≤ a < p,都存在唯一的 b 使得:
a × b ≡ 1 (mod p)
这个 b 就叫做 a 的"乘法逆元"或"倒数"
例子:p = 7
3 的逆元是多少?
3 × ? ≡ 1 (mod 7)
3 × 5 = 15 ≡ 1 (mod 7) ✓
所以在 mod 7 的世界里,3 的"倒数"就是 5!
这为什么如此特殊?
- 如果模数不是质数,某些数没有逆元(会导致计算破裂)
- 质数保证了完整性和可逆性
- 这是设计密码系统的必需条件
发现:法国数学家费马(Fermat),约 1640 年
如果 p 是质数,a 是不被 p 整除的整数,那么: a^(p-1) ≡ 1 (mod p)
具体例子:
p = 7, a = 3
3^(7-1) = 3^6 = 729
729 mod 7 = ?
729 ÷ 7 = 104 余 1
所以 3^6 ≡ 1 (mod 7) ✓
这对所有质数和不被它整除的数都成立!
为什么这很惊人?
这暗示了一个深层的结构:
mod p 的乘法世界有一个 p-1 的"周期"
从某个数开始,不断乘以自己,经过 p-1 步后会回到 1:
3^1 ≡ 3 (mod 7)
3^2 ≡ 2 (mod 7)
3^3 ≡ 6 (mod 7)
3^4 ≡ 4 (mod 7)
3^5 ≡ 5 (mod 7)
3^6 ≡ 1 (mod 7) ← 回到1
3^7 ≡ 3 (mod 7) ← 开始重复
这在密码学中的作用:
这个周期性给了我们一个关键想法:
如果我想保护一个数 a:
暴露 a^k mod p(某个幂次)
对方想要反推 a 和 k...
这很困难!因为有多个 (a, k) 组合都能产生同样的结果。
问题:怎样解方程?
一次方程:ax + b = 0
→ 直线(Euclid 几何)
→ 有明确的解
二次方程:ax² + bx + c = 0
→ 抛物线
→ 求根公式可解
三次及以上方程:???
→ 1500年代意大利数学家才发现三次公式
→ 四次方程也有(复杂)
→ 五次及以上... 无通用公式!(1824年才证明)
17世纪的数学家发现了一个特殊的方程:
y² = x³ + ax + b
这不是"通常的"方程形式。
为什么要研究它?
原始动力:
古人在研究椭圆轨道(行星运动)时,发现了与椭圆方程相关的积分。
"椭圆积分"导致了对形如 y² = x³ + ax + b 的曲线的兴趣。
(不是椭圆本身,但与椭圆问题相关,所以叫"椭圆曲线")
问题:什么是曲线上的"点"?
对于 y² = x³ + ax + b
任何满足这个方程的 (x, y) 对都在"曲线上"
例子:y² = x³ - x + 1
试试 x = 2:
y² = 8 - 2 + 1 = 7
y = ±√7
所以 (2, √7) 和 (2, -√7) 都在曲线上
几何形状:
y
↑
| •(x, y)
• | •
/ | /
────/─────┼──/────→ x
/ | /
• • •
这条曲线有特殊的性质:
- 关于 x 轴对称
- 有"无穷远点"
问题:我们能在椭圆曲线上"加"点吗?
17-18世纪的数学家开始思考一个激进的想法:
如果我们定义一个特殊的"加法",使得"两个曲线上的点相加仍然在曲线上",会怎样?
几何加法的定义:
要计算 P + Q(P 和 Q 是曲线上的两个不同的点):
步骤 1:画出过 P 和 Q 的直线
步骤 2:这条直线必定与曲线相交于第三个点 R'
步骤 3:P + Q 定义为 R' 关于 x 轴的镜像点 R
P + Q = R(R' 关于 x 轴的镜像)
为什么这样定义?
- 几何上优雅
- 满足交换律:P + Q = Q + P
- 满足结合律:(P + Q) + R = P + (Q + R)
- 存在单位元(无穷远点 O)
- 每个点有逆元(关于 x 轴的镜像)
数学验证(为什么这确实有效):
这个定义实际上创造了一个"群"结构。
群的定义需要:
1. 封闭性:a + b 也在群里 ✓(直线与三次曲线总相交于三点)
2. 结合律:(a+b)+c = a+(b+c) ✓(通过代数验证)
3. 单位元:存在 e 使 a+e = a ✓(无穷远点)
4. 逆元:∀a ∃b 使 a+b = e ✓(关于x轴镜像)
所以椭圆曲线上的点形成一个"阿贝尔群"!
问题:椭圆曲线在实数上很优美,但密码学需要什么?
真实数学:y² = x³ + ax + b (实数解)
密码数学:y² ≡ x³ + ax + b (mod p) (整数模p解)
为什么转换?
- 可计算性:实数涉及无限精度,计算机无法精确处理
- 有限性:在 mod p 下,只有有限个点,可以枚举
- 安全性:有限群上的离散对数问题是困难的
例子:y² ≡ x³ + 2x + 3 (mod 13)
我们逐个检查 x = 0, 1, 2, ..., 12
x = 0: y² ≡ 0 + 0 + 3 ≡ 3 (mod 13)
3 不是二次剩余(无解)
x = 1: y² ≡ 1 + 2 + 3 ≡ 6 (mod 13)
6 也不是二次剩余
x = 2: y² ≡ 8 + 4 + 3 ≡ 15 ≡ 2 (mod 13)
2 不是二次剩余
x = 3: y² ≡ 27 + 6 + 3 ≡ 36 ≡ 10 (mod 13)
10 不是二次剩余
x = 4: y² ≡ 64 + 8 + 3 ≡ 75 ≡ 10 (mod 13)
不是
...(继续所有 x)
结果:曲线上有大约 p 个点(p = 素数)
关键发现(Hasse定理,1936):
在 mod p 椭圆曲线上,点数 N 满足:
|N - (p + 1)| ≤ 2√p
这意味着,点数大约是 p 个(±√p 的误差)。
这个定理保证了椭圆曲线有"足够多"的点!
密码学的需求:
我们需要一个足够大的有限群,使得:
1. 群有足够的元素(N 要大)
→ 暴力破解困难
2. 群的结构是"随机的"
→ 没有快速攻击算法
椭圆曲线满足这两个条件!
1976年的密码困境:
在RSA发明之前,密码学有一个基本问题:
公开密钥加密需要什么?
需要一个函数 f,满足:
1. f(x) 易于计算
2. f^(-1) 难以计算
3. 但知道某个"秘密信息"时,f^(-1) 又容易计算
如何找到这样的函数?
发现:Diffie-Hellman,1976年
在 mod p(p是质数)的乘法群中:
g^x mod p 很容易计算
但要从 g^x 反推 x("离散对数")很困难!
为什么困难?
- g^1, g^2, g^3, ..., g^(p-1) 看起来很随机
- 没有已知的快速算法
- 等价于分解大整数的困难性(在某种意义上)
例子:
p = 13, g = 2
2^1 ≡ 2 (mod 13)
2^2 ≡ 4 (mod 13)
2^3 ≡ 8 (mod 13)
2^4 ≡ 3 (mod 13)
2^5 ≡ 6 (mod 13)
2^6 ≡ 12 (mod 13)
2^7 ≡ 11 (mod 13)
2^8 ≡ 9 (mod 13)
2^9 ≡ 5 (mod 13)
2^10 ≡ 10 (mod 13)
2^11 ≡ 7 (mod 13)
2^12 ≡ 1 (mod 13)
这个序列看起来很随机!
关键洞察:1985年独立发现(Koblitz和Miller)
同样的困难性在椭圆曲线上也存在!
给定点 P 和 Q = k×P(标量乘法):
易于计算:Q = k×P
困难计算:给定 Q 和 P,求 k
这就是"椭圆曲线离散对数问题"(ECDLP)
为什么更好?
RSA 需要 2048 位密钥(p, q 都是 1024 位)
ECC 只需 256 位密钥
安全性相同,但密钥小 8 倍!
原因:
- RSA 基于因数分解(有亚指数算法)
- ECC 基于离散对数(只有指数算法)
朴素方法:
5 × P = P + P + P + P + P
需要 4 次点加法
但如果 k 很大呢?
k = 2^256(256 位数)
则需要 2^256 - 1 次点加法...
永远计算不完!
关键想法:将 k 写成二进制
k = 5 = 101₂ = 4 + 0 + 1 = 2² + 2⁰
所以:
5 × P = (1×2² + 0×2¹ + 1×2⁰) × P
= 1×(2² × P) + 0×(2¹ × P) + 1×(2⁰ × P)
= 4P + P
= P + 4P
现在的问题变成:怎样快速计算 P, 2P, 4P, 8P, ..., 2^(n-1)P?
答案:每次倍增!
P → 2P(点加法)
2P → 4P(点加法)
4P → 8P(点加法)
...
总共只需要约 2×log₂(k) 次操作!
具体算法:
算法:Double-and-Add(倍增相加)
输入:k = 5 = 101₂(二进制), P
result = ∞(无穷远点,加法单位元)
对于 k 的每一位(从高到低):
bit = 第 i 位
result = 2 × result
if bit == 1:
result = result + P
步骤追踪(k = 5 = 101₂):
第1位(1): result = 2×∞ = ∞, result = ∞ + P = P
第2位(0): result = 2×P = 2P
第3位(1): result = 2×2P = 4P, result = 4P + P = 5P ✓
总操作数:2 次倍增 + 2 次加法 = 4 次
相比 4 次加法,差不多,但对大数优势明显
复杂度对比:
k = 256 位数(2^256)
朴素方法:需要 2^256 次操作(不可能)
二进制方法:需要约 2×256 = 512 次操作(可行!)
这是 3 × 10^77 倍的加速!
进一步的想法:
如果我们预计算 P, 3P, 5P, 7P, ..., 15P,
我们可以一次处理 4 位,而不是 1 位。
这又可以加速约 4 倍。
速度和预计算存储之间的权衡。
问题(公元前):
一个重要的文件(遗嘱、契约、法令)
危险 1:伪造
坏人声称"这是国王的命令"
危险 2:否认
国王说"我从没下过这个命令"
解决方案:签名(印章)
但...
- 印章可以被复制
- 在电子世界中,复制变得完美而容易
Diffie-Hellman 的想法:
如果我们有一对特殊的函数:
私函数 S(只有我知道):可以"签名"消息
公函数 V(所有人知道):可以"验证"签名
要求:
1. V(V(消息), 签名) 很容易验证
2. 没有私函数 S,伪造签名几乎不可能
3. S 和 V 必须不同(否则所有人都能签名)
这就是"非对称"密码学的核心想法。
Rivest, Shamir, Adleman 的解决方案:
公钥:(e, n) (n = p×q,两个大质数的乘积)
私钥:(d, n)
签名消息 m:
签名 s = m^d mod n (用私钥)
验证签名:
验证 s^e mod n == m (用公钥)
为什么有效?
(m^d)^e = m^(de) = m^(φ(n)k+1) ≡ m (mod n)
(基于欧拉定理)
但 RSA 在椭圆曲线上能用吗?
不能!RSA 需要乘法结构(模乘法)
椭圆曲线的是加法结构(点加法)
我们需要设计一个专门为椭圆曲线的签名方案。
问题:如何在椭圆曲线上实现签名?
Koblitz 和 Miller(1985)的想法:
我们能把 RSA 的想法转移到椭圆曲线吗?
RSA 用的是:m^d mod n
ECC 能用的是:d × P(标量乘法)
那签名能是:
签名 = d × hash(m) + d × hash(随机数)?
美国国家安全局提出,最终成为标准(FIPS 186-2)
关键洞察:使用一个不同的机制
不是直接暴露私钥的作用,而是设计一个"挑战-响应"系统。
设计原理:
签名的数学形式:
签名 = (r, s),其中:
k = 随机数
(x, y) = k × G (基点的标量倍)
r = x mod n (第一部分:x坐标模曲线阶)
s = k^(-1) × (hash(m) + d × r) (第二部分:涉及私钥和哈希)
验证时反推:
从 (r, s) 和公钥 Q = d×G,能反推出 k×G 吗?
是的!通过精妙的数学:
u1 = hash(m) / s mod n
u2 = r / s mod n
(x', y') = u1×G + u2×Q
验证 x' mod n == r
第一:正确性
如果签名生成正确,验证必然成功:
s = k^(-1) × (hash(m) + d × r)
ks = hash(m) + d × r
u1×G + u2×Q
= (hash(m)/s)×G + (r/s)×(d×G)
= (hash(m)/s)×G + (r×d/s)×G
= ((hash(m) + r×d) / s) × G
= ((ks) / s) × G (代入 ks = hash(m) + d×r)
= k × G
所以 x' = x,验证通过!✓
第二:安全性
为什么攻击者无法伪造签名?
如果攻击者想伪造签名 (r, s),他需要:
伪造 s,使得验证方程成立
但要这样做,他需要知道 k(随机数)
而 k 是随机选择的,对他隐藏的
或者,他需要从 Q = d×G 反推 d
但这就是椭圆曲线离散对数问题(已知不可解)
所以伪造签名在计算上是不可行的。
第三:不可否认性
为什么签名者无法否认签名?
签名证明签名者知道私钥 d。
(因为 s 的计算涉及 d)
只有知道 d 的人才能创造有效的 (r, s)。
所以签名者不能说"这不是我签的"。
为什么选择这个特定的形式?
设计者面对的选择:
选项1:直接形式
签名 = 私钥操作的结果
→ 简单但容易泄露私钥信息
选项2:挑战-响应形式(ECDSA)
签名 = 对随机挑战的响应
→ 复杂但保护私钥
数学家选择了选项2,因为:
- 随机性 k 提供了额外的安全层
- 即使哈希泄露了,k 的隐藏也保护了私钥
- 多个签名用不同的 k,更难通过分析攻击
危险:ECDSA 中的随机数 k 必须严格保密
1993 年 DSA 泄露事件:
- 索尼的 PlayStation 使用了不安全的随机数生成
- 结果被破解,私钥泄露
原因:k 被重复使用了两次
数学上的灾难:
假设两个签名用了同一个 k:
签名1:s1 = k^(-1) × (hash(m1) + d × r)
签名2:s2 = k^(-1) × (hash(m2) + d × r) (同一个 r,因为同一个 k)
两个方程相减:
s1 - s2 = k^(-1) × (hash(m1) - hash(m2))
攻击者可以解出:
k = (hash(m1) - hash(m2)) / (s1 - s2)
一旦知道 k,从 s1 方程能解出:
d = (s1 × k - hash(m1)) / r
私钥被完全破解!
2011年 Yannick Seurin 的论文提出:
如果我们从消息哈希和私钥推导 k(而不是随机选择),会怎样?
k = HMAC(私钥, 哈希(消息))
优点:
1. k 仍然对每个消息不同
2. 攻击者无法预测 k(因为不知道私钥)
3. 即使没有好的随机数生成器,也安全
4. 签名变得"确定的"(相同消息 + 私钥 = 相同签名)
缺点:
1. 签名中失去了"随机性"(虽然不是缺点,反而更好)
具体算法(简化版):
输入:私钥 d,消息 m,哈希函数 H
步骤1:计算消息哈希
h1 = H(m)
步骤2:初始化 HMAC
V = 0x01 0x01 ... (一串1)
K = 0x00 0x00 ... (一串0)
步骤3:更新 K 和 V(使用 HMAC)
K = HMAC(K, V || 0x00 || d || h1)
V = HMAC(K, V)
K = HMAC(K, V || 0x01 || d || h1)
V = HMAC(K, V)
步骤4:生成 k
while True:
T = 空
while len(T) < 需要的位数:
V = HMAC(K, V)
T = T || V
k = T mod n (n 是曲线的阶)
if 1 ≤ k < n:
return k ← 找到了!
K = HMAC(K, V || 0x00)
V = HMAC(K, V)
为什么这样设计?
1. 使用消息哈希:k 对不同消息不同 ✓
2. 使用私钥:只有知道私钥才能计算 k ✓
3. HMAC 的安全性保证 k 不可预测 ✓
4. 反复迭代直到 k 在有效范围内 ✓
在纯 Bash 中实现 ECC 的挑战:
问题1:大整数运算
解决:用字符串逐位实现加、乘、除、mod
问题2:有限域算术
解决:所有运算都在 mod p 下进行
问题3:椭圆曲线点运算
解决:实现点加法和点倍增的公式
问题4:ECDSA 算法
解决:实现签名和验证的完整流程
问题5:RFC 6979 确定性 k
解决:用 HMAC-SHA256 从消息推导 k
问题6:标准兼容性
解决:输出 ASN.1 DER 格式的签名
大整数加法(mod p):
# 从右到左逐位相加,处理进位
for ((i = 1; i <= max_len; i++)); do
digit_a="${a: -$i:1}"
digit_b="${b: -$i:1}"
sum=$((digit_a + digit_b + carry))
result="$((sum % 10))${result}"
carry=$((sum / 10))
done模逆元(扩展欧几里得算法):
# 找到 a 在 mod m 下的逆元
# 即找到 x 使得 a × x ≡ 1 (mod m)
extgcd() {
local a=$1 b=$2
if [[ $b -eq 0 ]]; then
echo "$a 1 0"
return
fi
local result=$(extgcd $b $((a % b)))
# 递归求解,然后回溯计算逆元
...
}点加法(在有限域上):
ec_point_add() {
local p1_x=$1 p1_y=$2
local p2_x=$3 p2_y=$4
local a=$5 p=$6
# 计算斜率 λ
local dx=$((p2_x - p1_x))
local dy=$((p2_y - p1_y))
lambda=$(mod_inverse $dx $p)
lambda=$(mod_mult $dy $lambda $p)
# 计算结果点
local x3=$((lambda * lambda - p1_x - p2_x))
local y3=$((lambda * (p1_x - x3) - p1_y))
x3=$((x3 % p))
y3=$((y3 % p))
echo "$x3 $y3"
}标量乘法(二进制方法):
ec_scalar_mult() {
local k=$1 # 标量
local px=$2 py=$3 # 点
local result_x="0" result_y="0" # 无穷远点
local cur_x=$px cur_y=$py
# 逐位处理 k 的二进制
while [[ $k -gt 0 ]]; do
if [[ $((k % 2)) -eq 1 ]]; then
# 当前位是1,加上当前点
result=$(ec_point_add $result_x $result_y $cur_x $cur_y ...)
fi
# 倍增当前点
cur=$(ec_point_double $cur_x $cur_y ...)
k=$((k / 2)) # 右移一位
done
echo "$result_x $result_y"
}ECDSA 签名:
ecdsa_sign() {
local message=$1
local private_key=$2
# 步骤1:哈希消息
hash=$(sha256 "$message")
# 步骤2:生成确定性 k(RFC 6979)
k=$(rfc6979_derive_k "$hash" "$private_key")
# 步骤3:计算 (x, y) = k × G
point=$(ec_scalar_mult $k $Gx $Gy)
x=${point% *}
# 步骤4:计算 r = x mod n
r=$((x % n))
# 步骤5:计算 s = k^(-1) × (hash + d × r)
k_inv=$(mod_inverse $k $n)
s=$(mod_mult $k_inv $((hash + d * r)) $n)
# 步骤6:输出 (r, s)
echo "$r $s"
}ECDSA 验证:
ecdsa_verify() {
local message=$1
local r=$2 s=$3
local public_key_x=$4 public_key_y=$5
# 步骤1:哈希消息
hash=$(sha256 "$message")
# 步骤2:计算 w = s^(-1) mod n
w=$(mod_inverse $s $n)
# 步骤3:计算 u1 = hash × w mod n
u1=$(mod_mult $hash $w $n)
# 步骤4:计算 u2 = r × w mod n
u2=$(mod_mult $r $w $n)
# 步骤5:计算 (x', y') = u1×G + u2×Q
p1=$(ec_scalar_mult $u1 $Gx $Gy)
p2=$(ec_scalar_mult $u2 $public_key_x $public_key_y)
result=$(ec_point_add $p1 $p2 ...)
# 步骤6:验证
x=${result% *}
if [[ $((x % n)) -eq $r ]]; then
echo "VALID"
else
echo "INVALID"
fi
}问题 ↓
↓
古人的计数 → 模运算的发明
↓
解决什么分配不均匀的问题? → 质数和互质的发现
↓
为什么某些数有特殊性质? → 费马小定理
↓
如何解高次方程? → 椭圆曲线的研究
↓
在有限域上怎样做代数? → 模 p 椭圆曲线
↓
如何在有限群上实现密码系统? → 离散对数问题
↓
怎样高效计算 k×P? → 二进制标量乘法
↓
如何证明消息真实性? → 数字签名
↓
怎样在椭圆曲线上签名? → ECDSA 的设计
↓
怎样让签名安全,避免随机数泄露? → RFC 6979
↓
实现 ↓
↓
bECCsh:完整的纯 Bash ECC
每一个概念都解决了前面发现的问题。 每一个问题都来自实际的需求。 这就是数学和密码学的真实进化过程。
这份文档展示的是:不是一堆公式,而是一个思想的演进过程。
每当你看到一个算法或定义时,问问自己:
✓ 为什么古人需要这个? ✓ 之前的方法有什么问题? ✓ 这个解决方案如何改进了? ✓ 下一个问题会是什么?
这就是深层理解数学的方式。