CRYPTO中的数论基础(更新中)
CRYPTO中的数论基础(更新中)
AiY0u本文持续更新中
数论简介:
数论(number theory),是纯粹数学的分支之一,主要研究整数的性质。
模运算
1. 模运算规则
a mod b (b>0,且a,b均为整数) 相当于许多编程语言中的a % b,表示a作为被除数,b作为除数时,计算所得到的余数
这里强调,除数b必须是正整数,而被除数a可以是负整数
2. 整除的概念
如果a mod b= 0,则称b整除a,记作b|a
如:15/5=3,则5|15
3. 模运算举例
15点是下午3点,19点是晚上7点,这其实就运用了模运算(x mod 12)
a为负整数时怎么算呢?
例如:-11 mod 4
我们可以让-11不停加上4
-11+4=-7,-7+4=-3,-3+4=1
所以-11 mod 4 = 1(即-11=4*(-3)+1)
最大公约数
1.公约数和最大公约数的概念
设整数a,b 如果存在整数d,使d|a,d|b,则称d是a和b的公因子(或公约数)
如果 d>0 ,且a和b的所有公因子都整除d,则称d是a和b的 最大公约数 ,记作gcd(a,b)
哎为什么这里没有限制公因子是正整数还是负整数嘞?
因为公因子可正可负可为0!
3和6的公因子:+1,-1,+3,-3
其中gcd(3,6) = 3
再有就是说,求最大公约数时可以把负号直接去掉来求:
1 | gcd(-3,6) = gcd(3,6) = 3 ; gcd(-3,-6) = gcd(3,6) = 3 |
互素
定义:
1 | 如果gcb(a,b) = 1,称a和b互素 |
存在这样一个定理:
1 | 如果gcd(a,b) = d,那么存在整数m,n 使得a=md,b=nd,且gcd(m,n)=1 |
例如gcd(4,6)=2 ,m=2,n=3,m和n互质
证明:
1 | 如果gcd(m,n)=t >1, |
欧几里得算法(辗转相除法)计算最大公约数
欧几里得算法的原理
不妨设a>=b>=0
1.b=0时,gcd(a,0)=a 任何数都是0的因子,所以这里是a
2.b!=0时,求gcd(a,b),许多情况下我们可以写出
1 | a=q*b+r |
假设gcd(a,b)=t, 那么上式写为:
1 | m*t=q*n*t+r |
1 | r=(m-q*n)t |
由此得到:t也是余数r的因子。这个结论对a和b的任意因子都成立,显然也对最大公因子成立
所以我们知道
1 | gcd(a,b)=gcd(b,r) |
计算过程
通过不断缩小问题规模,把求两个数的最大公约数转化为更简单的情况。
- 若较小的数是0,答案就是较大的数
- 比如求gcd(8,0)=8,因为所有数都能整除0
- 若两数都不为0,用除法转换问题:
- 用大数除以小数:70 ÷ 15 = 4 余 10(写作70 = 4×15 +10)
- 此时gcd(70,15) = gcd(15,10)(关键转换!)
- 继续对新数对重复这个过程
实操
gcd(70,15)=gcd(15,10)=gcd(10,5)=gcd(5,0)=5
- 70 ÷ 15 = 4 余10 → 转为求gcd(15,10)
- 15 ÷ 10 = 1 余5 → 转为求gcd(10,5)
- 10 ÷ 5 = 2 余0 → 转为求gcd(5,0)
- 出现0时,答案就是剩下的5
代码实现
1 | def gcd(a,b): |
扩展的欧几里得算法
扩展欧几里得算法是欧几里得算法的升级版,它不仅计算两个数的最大公约数(GCD),还能找到一组关键系数(称为贝祖系数),使得这两个数的线性组合等于它们的最大公约数。
贝祖定理:
1 | 若 d=gcd(a,b),则存在整数 s,t使得 as+bt=d |
1 | 特别地,若 gcd(a,b)=1,则方程 as+bt=1 有解(即 a 和 b 互质时存在逆元)。 |
而扩展的欧几里得算法就是用来计算上述定理中的s和t
原理:
根据欧几里得算法的逆过程,这里以gcd(70,15)为例
前文已经写出了欧几里得算法的过程,我们只需根据它一步一步回代
1 | 5=15×1−10×1 |
1 | 其中 10=70×1+15×(−4),代入得: |
代码实现
1 | def extended_gcd(a, b): |
==============================================================================================
施工区域
最小公倍数
引入:天干地支纪年法中,天干有10个,地支有12个
我们知道60年1甲子,天干循环一次周期是10,地支循环周期是12;
从一次出现甲子到下一次出现甲子,不仅需要天干中出现甲,地支中出现子,则刚好需要天干循环整数次,地支循环整数次,显然,这就变成了一个最小公倍数问题,每60年能让天干循环6次,地支循环5次
$$
设a,b∈Z,如果m∈Z分别是a和b的倍数,m称为a和b的公倍数
$$
$$
a,b≠0,如果m是所有正的公倍数中最小的,那么m叫做a和b的最小公倍数,记为m=lcm(a,b)
$$
$$
如果a=0或者b=0:lcm(a,b)=0
$$
lcm(a,b)=ab/gcd(a,b)
同余
费马小定理
模逆元
二次剩余
一个整数x对另一个整数p的二次剩余指的是计算x² mod p的结果(x的平方除以p得到的余数)
1 | 当存在一个整数x使得x² ≡ a mod p,称a是模p的二次剩余 |
它还有这样的运算性质:
1 | 二次剩余 * 二次剩余 = 二次剩余 |
检验整数是否是二次剩余参见下文勒让德符号
勒让德符号
勒让德符号(Legendre Symbol)提供了一种有效的方法来确定整数a是否是模奇数素数p的二次余数
以cryptohack中的题目为例:
题目要求:
Now for the flag. Given the following 1024 bit prime and 10 integers, find the quadratic residue and then calculate its square root; the square root is your flag. Of the two possible roots, submit the larger one as your answer.
给定1024bit的质数和10个整数,找到二次剩余并且计算它的模平方根,取较大的一个作为flag
我们首先根据勒让德符号,得到哪一个整数是二次剩余。代码如下:
1 | p = 101524035174539890485408575671085261788758965189060164484385690801466167356667036677932998889725476582421738788500738738503134356158197247473850273565349249573867251280253564698939768700489401960767007716413932851838937641880157263936985954881657889497583485535527613578457628399173971810541670838543309159139 |
这里提一句,python判断是否是二次剩余的写法:
1 | if pow(n,(p-1)//2,p) == 1: |
第三行写的是p-1,因为python的pow函数计算结果不会为负。
之后求它的模平方根,需要用到一定的代数运算。
1 | #求a模p意义下的平方根 |
Tonelli-Shanks算法
**Tonelli-Shanks算法(托内利-尚克斯算法)**可以计算模素数下的平方根。
python实现:
1 | def legendre_symbol(a, p): |
也可以使用各种库,如sympy
1 | from sympy.ntheory.residue_ntheory import nthroot_mod |
这里nthroot_mod函数相当于计算x² ≡ a (mod p)
关于常用库的常用函数的文章火热筹备中。