本文为密码学的数学基础(王小云,王明强著)的读书笔记,将自己认为比较好的定理的证明与习题做了整理,同时对一些常用的算法做了拓展,以及C语言的实现,水平有限,如有错误,欢迎指正。(PS:官方编辑器好多公式不方便编辑,于是便从latex中粘过来图片,使局部地区不太美观,多多包涵)
目录
素数,整除
两个定理
定理1.4:若a为合数,则a的最小真因子为素数。
定理1.5:素数又无穷多个。
证明:
1.4:
反证法,假设a为合数,即
a
>
2
a>2
a>2,设其最小真因子为d,那么假设d为非素数,即为合数,存在
d
′
∣
d
d'|d
d′∣d,因此
d
′
∣
a
d'|a
d′∣a,所以,与d为最小真因子矛盾,得证.
1.5:
反证法,假设素数为有限个,为
p
1
,
p
2
,
p
3
,
.
.
.
p
k
p_1,p_2,p_3,...p_k
p1,p2,p3,...pk,考虑
a
=
p
1
p
2
.
.
.
p
k
+
1
,
a=p_1p_2...p_k+1,
a=p1p2...pk+1,那么根据定理1.4,可以得到a的最小真因子一定为
p
1
,
p
2
,
p
3
,
.
.
.
p
k
p_1,p_2,p_3,...p_k
p1,p2,p3,...pk中某一个素数,记作p,则
p
为
p
i
(
i
=
1
,
2
,
.
.
.
k
)
中
某
一
个
,
p为p_{i}(i=1,2,...k)中某一个,
p为pi(i=1,2,...k)中某一个,所以
p
∣
a
,
p
∣
p
1
p
2
.
.
.
p
k
p|a,p|p_{1}p_{2}...p_k
p∣a,p∣p1p2...pk同时成立,所以推出p|1,这与p为素数矛盾,得证.
最大公因子,最小公倍数
数学符号定义
求a和b的最大公因子:
d
=
g
c
d
(
a
,
b
)
=
(
a
,
b
)
d=gcd(a,b)=(a,b)
d=gcd(a,b)=(a,b)
求a和b的最小公倍数:
[
a
,
b
]
[a,b]
[a,b]
一道证明题
题目:
设a是奇数,证明:
- 一定存在正整数 d ≤ a − 1 , 使 得 a ∣ 2 d − 1 d\leq a-1,使得a|2^{d}-1 d≤a−1,使得a∣2d−1
- 必有正整数d,使 ( 2 d − 3 , a ) = 1 (2^d-3,a)=1 (2d−3,a)=1
证明:
考虑以下a个数
2
0
,
2
1
,
2
2
,
.
.
.
2
a
−
1
2^0,2^1,2^2,...2^{a-1}
20,21,22,...2a−1由
a
∤
2
j
(
0
≤
j
<
a
)
a\nmid2^j(0\leq j<a )
a∤2j(0≤j<a)以及带余除法可以得到知道,对于每一个j,
0
≤
j
<
a
0 \leq j<a
0≤j<a,存在
q
j
,
r
j
q_j,r_j
qj,rj使得
2
j
=
q
j
a
+
r
j
,
0
<
r
j
<
a
2^j=q_ja+r_j,0<r_j<a
2j=qja+rj,0<rj<a所以a个余数
r
0
,
r
1
,
.
.
.
r
a
−
1
r_0,r_1,...r_{a-1}
r0,r1,...ra−1 仅仅可能取a-1个值,根据抽屉原理知道其中必有两个余数相等,不妨设
0
≤
i
<
k
<
a
0\leq i<k<a
0≤i<k<a,且
r
i
=
r
k
r_i=r_k
ri=rk,因而有
a
(
q
k
−
q
i
)
=
2
k
−
2
i
=
2
i
(
2
k
−
i
−
1
)
a(q_k-q_i)=2^k-2^i=2^i(2^{k-i}-1)
a(qk−qi)=2k−2i=2i(2k−i−1)由
(
a
,
2
)
=
1
(a,2)=1
(a,2)=1,可以得到
a
∣
2
k
−
i
−
1
a|2^{k-i}-1
a∣2k−i−1取
d
=
k
−
i
d=k-i
d=k−i即满足要求.得证
2.
由1知,存在d使得
a
∣
2
d
−
1
a|2^{d}-1
a∣2d−1,可以推出
(
2
d
−
3
,
a
)
=
(
2
d
−
1
−
2
,
a
)
=
(
−
2
,
a
)
=
1
(2^d-3,a)=(2^d-1-2,a)=(-2,a)=1
(2d−3,a)=(2d−1−2,a)=(−2,a)=1得证.
Euclid
算法定义与应用
定义:
Euclid算法重要结论:
(1)
r
k
=
(
a
,
b
)
r_{k}=(a, b)
rk=(a,b)
(2) 存在整数
x
0
,
x
1
x_{0}, x_{1}
x0,x1 使
(
a
,
b
)
=
a
x
0
+
b
x
1
(a, b)=a x_{0}+b x_{1}
(a,b)=ax0+bx1\
证明:
(1) 从Euclid算法定义的最后一个式子,依次往上推,可得
r
k
=
(
r
k
,
r
k
−
1
)
=
⋯
=
(
r
1
,
r
0
)
=
(
r
0
,
b
)
=
(
a
,
b
)
r_{k}=\left(r_{k}, r_{k-1}\right)=\cdots=\left(r_{1}, r_{0}\right)=\left(r_{0}, b\right)=(a, b)
rk=(rk,rk−1)=⋯=(r1,r0)=(r0,b)=(a,b)
结论成立.
(2) 由 Euclid 算法中的第
k
+
1
k+1
k+1 式,
(
a
,
b
)
(a, b)
(a,b) 可表成
r
k
−
1
r_{k-1}
rk−1 和
r
k
−
2
r_{k-2}
rk−2 的整系数线性组合, 利用第
k
+
1
k+1
k+1 式可消去
r
k
−
1
,
r_{k-1},
rk−1, 得到
(
a
,
b
)
(a, b)
(a,b) 的关于
r
k
−
2
r_{k-2}
rk−2 和
r
k
−
3
r_{k-3}
rk−3 的整系数线性组合. 这样依次利用第
k
,
k
−
1
,
⋯
,
2
,
1
k, k-1, \cdots, 2,1
k,k−1,⋯,2,1 式, 就得到
a
a
a 和
b
b
b 的整系数线性组合.
Euclid应用之一:求最大公因子
//输入参数设定:a>b(进入函数前需要判断,使a>b),可以加快求解速度,
//避免了递归函数中的判断
int Euclid(int a,int b)
{
if(!b)
return a;//如果b=0,a为最大公因子,返回a
return Euclid(b,a%b);
}
拓展Euclid算法介绍与实现
拓展Euclid算法在求解不定方程和密码学中有着极其重要的作用,比如:
- 在求解不定方程中,常常用Euclid求解.
- 当两个数互素,即最大公因子为1时,在RSA加密算法中,常常利用拓展Eclid,根据公钥求私钥.
- 待补充…
通过拓展Euclid算法求解两个数a和b的线性组合式,是拓展Eclid算法的重要应用,即求解满足
a
x
+
b
y
=
g
c
d
(
a
,
b
)
ax+by=gcd(a,b)
ax+by=gcd(a,b)的x,y值,可以作为不定方程的某一个特解.如果
g
c
d
(
a
,
b
)
=
1
gcd(a,b)=1
gcd(a,b)=1再利用同余性质,进行求a或b的逆.
下面为求解满足
a
x
+
b
y
=
g
c
d
(
a
,
b
)
ax+by=gcd(a,b)
ax+by=gcd(a,b)的x,y值的代码与解析.
对x,y值求解有两种方法,一种递归式方案,一种非递归式方案,递归方案代码简单,阅读代码比较困难,资源开销较大.非递归方案代码较复杂,但是逻辑简单,易读,资源开销较小.下面,对其分别进行解析:
非递归方案:
图片来源
C语言代码:
//输入参数设定:a>b(进入函数前需要判断,使a>b),gcd为a和b的最大公因子,x,y为相应解
void ex_Euclid_Non_recursive(int a, int b, int& gcd, int& x, int& y)
{
int r_1 = a, r0 = b, x_1 = 1, y_1 = 0,
x0 = 0, y0 = 1,x1=1,y1=0, q1,tempX,tempY,Temp;//初始化,r_{-1}定义为r_1,其余类推
if (r0)
{
q1 = r_1 / r0;//初始化
x1 = 1, y1 = -q1;
while (r_1 % r0)
{
q1 = r_1 / r0;//初始化
tempX = x1, tempY = y1;//将x1,y1存储到临时变量中
x1 = x_1 - q1 * x0;
y1 = y_1 - q1 * y0;
//cout << x1 << '\t' << y1 << endl;
x_1 = x0, y_1 = y0;
x0 = tempX, y0 = tempY;
Temp = r_1;//将r_1存储到临时变量中
r_1 = r0;
r0 = Temp % r0;
//cout << r_1 << '\t' << r0 << endl;
}
}
gcd = r0;
x = x1, y = y1;
}
递归方案:
求解满足
a
x
+
b
y
=
g
c
d
(
a
,
b
)
ax+by=gcd(a,b)
ax+by=gcd(a,b)的x,y值.我们可以换一种思维:
和非递归方案类似,我们试图寻找
x
1
和
x
2
x_1和x_2
x1和x2,
y
1
和
y
2
y_1和y_2
y1和y2之间的关系,不过不同的是,在非递归方案中,我们找到的是由已知的
x
−
1
,
y
−
1
,
x
0
,
y
0
x_{-1},y_{-1},x_0,y_0
x−1,y−1,x0,y0求解
x
1
,
y
1
x_1,y_1
x1,y1的方案,即按照计算的过程,循序渐进寻找答案,这次我们寻找一种反向的求解方法,即由
x
2
,
y
2
x_2,y_2
x2,y2求解
x
1
,
y
1
x_1,y_1
x1,y1,这就需要我们进行利用递归函数特性,进行求解:
通过欧几里得算法定义观察以下两个等式**(注意:以下的%为C语言种的含义,即取余,/为C语言含义,即除法取整)**
a
x
1
+
b
y
1
=
g
c
d
(
a
,
b
)
ax_1+by_1=gcd(a,b)
ax1+by1=gcd(a,b)
b
x
2
+
(
a
%
b
)
y
2
=
g
c
d
(
b
,
a
%
b
)
bx_2+(a\%b)y_2=gcd(b,a\%b)
bx2+(a%b)y2=gcd(b,a%b)由于
a
x
1
+
b
y
1
=
b
x
2
+
(
a
%
b
)
y
2
=
g
c
d
(
a
,
b
)
=
g
c
d
(
b
,
a
%
b
)
ax_1+by_1=bx_2+(a\%b)y_2=gcd(a,b)=gcd(b,a\%b)
ax1+by1=bx2+(a%b)y2=gcd(a,b)=gcd(b,a%b)而
a
%
b
=
a
−
(
a
/
b
)
∗
b
a\%b=a-(a/b)*b
a%b=a−(a/b)∗b
整理以上四个等式可以得到:
a
x
1
+
b
y
1
=
b
x
2
+
(
a
−
(
a
/
b
)
∗
b
)
y
2
ax_1+by_1=bx_2+(a-(a/b)*b)y_2
ax1+by1=bx2+(a−(a/b)∗b)y2待定系数法化简后得到:
x
1
=
y
2
x_1=y_2
x1=y2
y
1
=
x
2
−
(
a
/
b
)
y
2
y_1=x_2-(a/b)y_2
y1=x2−(a/b)y2以上两式即为我们得到的递归等式,函数出口为:
a
%
b
=
0
a\%b=0
a%b=0,此时x=1,y=0.
附上代码:
void ex_Euclid_recursive(int a, int b, int& gcd, int& x, int& y)
{
if (b == 0)//递归函数出口
{
x = 1;
y = 0;
gcd = a;
}
else
{
ex_Euclid_recursive(b, a % b, gcd, y, x);
//此时x为y_2,y为x_2,理解这句话是理解此递归函数的关键
y -= x * (a / b);
}
}
可能代码阅读难度比较大,我也是理解了好几个小时才啃下这一部分,但是,当想明白后,还是蛮有成就感的,加油!!
递归与非递归方案函数代码+测试代码:
#include<iostream>
using namespace std;
inline void swap(int& a, int& b) { a ^= b ^= a ^= b; }
void ex_Eclid_Non_recursive(int a, int b, int& gcd, int& x, int& y)
{
int r_1 = a, r0 = b, x_1 = 1, y_1 = 0, x0 = 0, y0 = 1,x1=1,y1=0, q1,tempX,tempY,Temp;//初始化
if (r0)
{
q1 = r_1 / r0;//初始化
x1 = 1, y1 = -q1;
while (r_1 % r0)
{
q1 = r_1 / r0;//初始化
tempX = x1, tempY = y1;//将x1,y1存储到临时变量中
x1 = x_1 - q1 * x0;
y1 = y_1 - q1 * y0;
//cout << x1 << '\t' << y1 << endl;
x_1 = x0, y_1 = y0;
x0 = tempX, y0 = tempY;
Temp = r_1;//将r_1存储到临时变量中
r_1 = r0;
r0 = Temp % r0;
//cout << r_1 << '\t' << r0 << endl;
}
}
gcd = r0;
x = x1, y = y1;
}
void ex_Eclid_recursive(int a, int b, int& gcd, int& x, int& y)
{
if (b == 0)
{
x = 1;
y = 0;
gcd = a;
}
else
{
ex_Eclid_recursive(b, a % b, gcd, y, x);
y -= x * (a / b);
}
}
int main()
{
int a = 11, b = 1732, gcd, x, y;
if (a < b)swap(a, b), swap(x, y);
ex_Eclid_Non_recursive(a, b,gcd, x, y);
cout << "非递归方案:\n"<<"gcd=" << gcd << '\t' << "x=" << x << '\t' << "y=" << y << endl;
cout << gcd << " = " << a << "X" << x << "+" << b << "X" << y << endl;
gcd=0, x=0, y=0;//初始化为0,继续测试
ex_Eclid_recursive(a, b, gcd, x, y);
cout << "递归方案:\n" << "gcd=" << gcd << '\t' << "x=" << x << '\t' << "y=" << y << endl;
cout << gcd << " = " << a << "X" << x << "+" << b << "X" << y << endl;
return 0;
}
几个习题
-
对任意正整数 a 有 5 ∣ a 5 − a 5 \mid a^{5}-a 5∣a5−a
-
13 ∣ a 2 − 7 b 2 13 \mid a^{2}-7 b^{2} 13∣a2−7b2 的充要条件是 13 ∣ a , 13 ∣ b 13|a, 13| b 13∣a,13∣b
-
当 n > 1 n>1 n>1 时, 1 + 1 / 2 + ⋯ + 1 / n 1+1 / 2+\cdots+1 / n 1+1/2+⋯+1/n 不是整数
习题参考答案
- 充分性:
13
∣
a
2
−
7
b
2
13 \mid a^{2}-7 b^{2}
13∣a2−7b2 时,我们要推出
13
∣
a
,
13
∣
b
13|a, 13| b
13∣a,13∣b:
13 ∣ a 2 − 7 b 2 13 \mid a^{2}-7 b^{2} 13∣a2−7b2等价于 a 2 = 7 b 2 ( m o d 13 ) a^{2}=7 b^{2}(mod\ 13) a2=7b2(mod 13),可以通过遍历a,b,a和b的取值范围均为0~12,进a=b=0时满足等式.所以充分性得证.(应该有更好的方法,暂时忘了,想到再补充…)
必要性: 13 ∣ a , 13 ∣ b 13|a, 13| b 13∣a,13∣b时,我们要推出 13 ∣ a 2 − 7 b 2 13 \mid a^{2}-7 b^{2} 13∣a2−7b2:
设 a = 13 r , b = 13 s , a=13r,b=13s, a=13r,b=13s,带入 13 ∣ a 2 − 7 b 2 13 \mid a^{2}-7 b^{2} 13∣a2−7b2,满足,得证. - 假设存在这样一个n, 设k是不大于n的素数 ,由于素数和它的两倍 之间一定存在一个素数 ,所以n不大于2k ,即所有的分母中只有k含有因子k
,因为级数是整数 。
所以除开 1 / k 1/k 1/k的其他数的和的小数部分是 ( k − 1 ) / k (k-1)/k (k−1)/k ,因为其它分母中均不含有素数k这个因子 ,所以这些分数的和也不含有素数k
两者矛盾
所以不存在这样一个n