ECC(Elliptic Curve Cryptography)椭圆曲线密码详解

椭圆曲线密码基于离散对数难题
公钥密码
ECC 非对称密钥功能:加密、签名、密钥交换
ECC是RSA的后继更短的密钥长度、更快的签名、更快的密钥协商

私钥长度为256bits, 32字节。大小在曲线的域范围内(field size),256bits的整数。此范围内任意整数都是合法的私钥。
公钥为曲线上的点(EC points),坐标为{x,y}.能够压缩为一个坐标长度+1bit,为压缩的公钥(compressed public key)。

不同的椭圆曲线具有不同的安全级别、不同的性能、不同的密钥长度。
ECC曲线的一些术语:
名字:secp256k1、Curve25519
域长度:定义密钥长度,如256bits
安全强度:域长度/2 或更小
性能:operations/sec
密钥长度:OpenSSL, OpenSSH and Bitcoin 默认256bits。
256-bit (curves secp256k1 and Curve25519),384-bit (curves p384 and secp384r1),…

ECC算法:基于有限域上的数学
ECC数字签名: ECDSA (for classical curves) EdDSA (for twisted Edwards curves)
ECC加密: ECIES EEECC (EC-based ElGamal).
ECC 密钥交换:ECDH, X25519 and FHMQV.
所有这些算法采用公钥、私钥对。私钥是整数,公钥是曲线上的点EC point。
在这里插入图片描述
包含所有的{x,y}
简化后的曲线(Weierstras form)y^2 = x ^ 3 + ax + b
令: a = 0 and b = 7
y^2 = x ^ 3 + 7 ( NIST curve secp256k1 (used in Bitcoin))。如下:
ECC(Elliptic Curve Cryptography)椭圆曲线密码详解_第1张图片
图形生成参考链接: https://www.desmos.com/calculator/ialhd71we3?lang=zh-CN
ECC使用的椭圆曲线定义在有限域p上,p是素数,p>3
2m 域大小为 p = 2m 为一方阵(the field is a square matrix of size p x p)
曲线上的点不连续,限定为离散的整数。域内的点加、点乘结果还在曲线上。
有限域p上的椭圆曲线等式:
y^2 ≡ x ^ 3 + ax + b (mod p)

RSA的密钥空间为域ℤp上的整数 [0…p-1] 。
ECC的密钥用点{x,y},在Galois field p 上,x和y都是 [0…p-1]的整数。
有限域p 上的椭圆曲线满足:
整数坐标 {x, y}集合,满足0 ≤ x, y < p
{x,y}在曲线上: y^2 ≡ x ^ 3 + ax + b (mod p)
一个有限域17的例子:
y ^ 2 ≡ x ^3 + 7 (mod 17)

ECC(Elliptic Curve Cryptography)椭圆曲线密码详解_第2张图片

一些计算:
是否在曲线上:
x^3 + 7 - y ^ 2 ≡ 0 (mod 17)
如 P {5, 8} 在曲线上 因为 (53 + 7 - 82) % 17 == 0
ECC(Elliptic Curve Cryptography)椭圆曲线密码详解_第3张图片
点乘:
曲线上的两个点相加得到曲线上另一个点——点加. G 加上自己, 结果 G + G = 2 * G. I类推 3 * G … 结果也在域内,这是域的封闭性。 这就是点乘的定义。
P = k * G
当k=0时,得到无穷点O “infinity”.
例子:
P = k * G = 6 * {15, 13} = {5, 8}
ECC(Elliptic Curve Cryptography)椭圆曲线密码详解_第4张图片
点加的计算方法:
假定P点为(x1, y1),Q点为(x2, y2),P+Q为(x3, y3),因此P+Q由以下规则确定:
若椭圆曲线上两个点相同,则
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
若椭圆曲线上两个点不同
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
[https://blog.csdn.net/Catherine_qingzhu/article/details/107288195]
图示参考:http://star.aust.edu.cn/xjfang/crypto/add.html
上面涉及到分数取模,如下:
假设求 \frac{b}{a} \ mod \ p
, 等价于求在这里插入图片描述
第一种用快速幂模:
由费马小定理
在这里插入图片描述
进一步:
在这里插入图片描述
在这里插入图片描述
取模运算:
(ab)%c=(a%c)(b%c)%c
a^b%c
对于b我们可以拆成二进制的形式
b=b0+b12+b22 ^ 2+…+bn2^n
那么我们的a^b运算就可以拆解成
a ^ b0 * a ^ b1 2^ 1… * a ^ (bn2^n)
我们真正想要的其实是b的非0二进制位
a ^ (2 ^ x)
a^ (2^n)
实例化容易理解:a^11%p
11=1011b=2^ 0 + 2 ^1 + 0 * 2 ^2 + 2 ^3 @1
a^ (2^ 0 + 2 ^1 + 2 ^3)%p = (a ^ 1 * a ^ 2 * a^ 8)%p =
((a%p * a ^ 2%p)%p * a^ 8%p)%p @2
再结合下面代码,b&1说明上面@1式:1011对应位置为1(通过了b>>=1的不断右移),也即@2式,对应的(a
a)%c会添加进@2里面。如@1的第3个二进制位为0. 对应a = ((a ^ 2%p) * (a ^ 2%p)) % p = (a ^ 2 * a ^ 2) %p = a ^4 %p.
但是b>>=1后 刚好b最低位为0,a ^4 %p不会加入@2.依次类推。

#include 
int fast_pow(int a,int b,int c)
{
    int ans=1;   ///记录结果
    a=a%c;   ///预处理,使得a处于c的数据范围之下
    while(b!=0)
    {
        if(b&1)///奇数
        {
            ans=(ans*a)%c;///消除指数为奇数的影响
        }
        b>>=1;    ///二进制的移位操作,不断的遍历b的二进制位
        a=(a*a)%c;   ///不断的加倍
    }
    return ans;
}

//递归方法
/*
typedef long long ll;
ll fast_pow(ll x,ll n,ll p)
{
    ll temp;
    x=x%p;
    if(n==0)///终止条件
    {
        return 1;
    }
    temp=fast_pow((x*x)%p,n>>1,p);
    if(n&1)
    {
        temp =temp*x%p;///消除指数为奇数的影响
    }
    return temp%p;
}
*/

int main() {
	long point[2] = {15, 13};
	int a = 0; 
	int p = 17;
	
	
	long x,y,Rx,Ry;

	long val;
	long aaa=(3*point[0]*point[0] + a);
        long bbb=(2*point[1]);
        if (aaa % bbb !=0){
	    //y = (aaa * bbb^-1)%17 = ((aaa % 17) * (bbb^-1%17))%17 = ((aaa % 17) * (bbb^(17-2)%17))%17 
	    y = ((aaa % 17) * fast_pow(bbb,(17-2),17))%17;
	}
        else
            y=(aaa/bbb) % 17;
	
	Rx=(y * y-point[0] - point[0])%17;
	Ry=(y*(point[0]-Rx) - point[1])%17;

	printf("x %ld, y %ld\n", Rx, Ry);//{2,10}
}

第二种方法,用拓展欧几里得算法求逆元
a^-1 为a 和 p的乘法逆元,也就是说 a 与 a ^ -1 的乘积模 p 的余数为 1.
计算乘法逆元,可以通过拓展欧几里得计算得到。
[https://www.jianshu.com/p/eece4117cb63]
先看看欧几里得算法求最大公约数,最大公约数(Greatest Common Divisor, GCD),是指2个或N个整数共有约数中最大的一个。a,b的最大公约数记为(a, b)。相对应的是最小公倍数,记为[a, b]。
在求最大公约数的几种方法中,欧几里得算法(辗转相除法)最为出名:

计算(a, b), 若b是0,则最大公约数为a;否则。将a除以b得到余数r,a和b的最大公约数就是b和r的最大公约数,即:(a, b) = (b, r)。

static int gcd(int a ,int b){
      if(b == 0){
            return a;
      }else{
            return gcd(b, a%b);
      }
}

求a模p的逆元x,使得 (a * x ) % p = 1, 该方程等价于 a * x = 1 + y * p (y为整数),也等价于 a * x - y * p = 1。因此求解x的过程就是求解该二元一次方程(a和p已知,求解x,y),即求a模p的逆元x。[https://www.cnblogs.com/GjqDream/p/11537934.html]
扩展欧几里德算法:
引理:存在 x , y 使得 gcd(a,b)=ax+by
证明:
当 b=0 时,gcd(a,b)=a,此时 x=1 , y=0
当 b!=0 时,
设 a * x1 + b * y1 = gcd(a, b) = gcd(b, a % b)=b * x2 + (a % b) * y2
又因a % b = a - a / b * b
a * x1 + b * y1 = b * x2 + a * y2 - a / b * b * y2
a * x1 + b * y1 = a * y2 + b * x2 - b * a / b * y2
a * x1 + b * y1 = a * y2 + b * (x2 - a / b * y2)
解得 x1 = y2 , y1 = x2 - a / b * y2
因为当 b=0 时存在 x , y 为最后一组解
而每一组的解可根据后一组得到
所以第一组的解 x , y 必然存在
得证
根据上面的证明,在实现的时候采用递归做法
先递归进入下一层,等到到达最后一层即 b=0 时就返回x=1 , y=0
再根据 x1=y2 , y1=x2-a/b*y2 ( x2 与 y2 为下一层的 x 与 y ) 得到当层的解
不断算出当层的解并返回,最终返回至第一层,得到原解

代码如下:

#include 
long get_gcd(long a, long b) {
	long remainder = a % b;
	while(remainder != 0) {
		a = b;
		b = remainder;
		remainder = a % b;
	}
	return b;
}

//拓展欧几里得算法求线性方程的x与y  a * x = 1 + y * b (y为整数)
//a * x => 1 mod b  最终的x即为a的乘法逆元
void get_(long a, long b, long *x, long *y){
	long k,yu, x1, y1;
	if (b == 0) {
		*x = 1;
		*y = 0;
	} else{
		k = a / b;
		yu = a % b;
		get_(b, yu, &x1, &y1);
		*x= y1;
		*y = x1 - k * y1;
	}	
}

long inverse(long a, long b) {
	long m = b;
	long x, y;

	if (get_gcd(a,b) == 1) {
		get_(a,b,&x,&y);	
		return x;
	}
		
	return -1;
}
int main() {
	long point[2] = {15, 13};
	int a = 0; 
	int p = 17;
	
	
	long x,y,Rx,Ry;

	long val;
	long aaa=(3*point[0]*point[0] + a);
        long bbb=(2*point[1]);
        if (aaa % bbb !=0){
            val=inverse(bbb,17);
            y=(aaa*val) % 17;
	}
        else
            y=(aaa/bbb) % 17;
	
	Rx=(y * y-point[0] - point[0])%17;
	Ry=(y*(point[0]-Rx) - point[1])%17;

	printf("x %ld, y %ld\n", Rx, Ry);//{2,10}
}

可视图:
[http://star.aust.edu.cn/xjfang/crypto/add.html]
ECC(Elliptic Curve Cryptography)椭圆曲线密码详解_第5张图片
最后是多倍点KG的计算:
方法1 平方和算法
ECC(Elliptic Curve Cryptography)椭圆曲线密码详解_第6张图片

#include 
void addG(long point[2], long a) {
	long Rx,Ry,y;
	long aaa=(3*point[0]*point[0] + a);
        long bbb=(2*point[1]);
        if (aaa % bbb !=0){
            //val=yunsle(bbb,17);
            //y=(aaa*val) % 17;


	    //y = (aaa * bbb^-1)%17 = ((aaa % 17) * (bbb^-1%17))%17 = ((aaa % 17) * (bbb^(17-2)%17))%17 
	    y = ((aaa % 17) * fast_pow(bbb,(17-2),17))%17;
	}
        else
            y=(aaa/bbb) % 17;
	
	Rx=(y * y-point[0] - point[0])%17;if (Rx < 0) Rx += 17;//-9 mod 17 = 8  不同的语言不一样,c得-9,Python得8,手动纠正一下,因为域在正整数内
	Ry=(y*(point[0]-Rx) - point[1])%17;if (Ry < 0) Ry += 17;

	point[0] = Rx;
	point[1] = Ry;
}

//G1=G1+G2; G1!=G2
void addG1G2(long G1[2], long G2[2]){
	long Rx,Ry,y;

	if (G1[0] == 0 && G1[1] == 0) {
		G1[0] = G2[0];
		G1[1] = G2[1];
	
		return;
	}

	long aaa=(G2[1] - G1[1]);
    long bbb=(G2[0] - G1[0]);
        if (aaa % bbb !=0){
            //val=yunsle(bbb,17);
            //y=(aaa*val) % 17;


	    //y = (aaa * bbb^-1)%17 = ((aaa % 17) * (bbb^-1%17))%17 = ((aaa % 17) * (bbb^(17-2)%17))%17 
	    y = ((aaa % 17) * fast_pow(bbb,(17-2),17))%17;
	}
        else
            y=(aaa/bbb) % 17;
	
	Rx=(y * y-G2[0] - G1[0])%17;if (Rx < 0) Rx += 17;
	Ry=(y*(G2[0]-Rx) - G2[1])%17;if (Ry < 0) Ry += 17;

	G1[0] = Rx;
	G1[1] = Ry;
}
void pingfanghe_kp(unsigned int k, long point[2], long G[2]){
	if (k <= 0){
		return;
	}

	int i = sizeof(unsigned int) * 8 - 1;
	
	for (; i >= 0; i--) {
		if (k & (1 << i))
			break;
	}

	G[0] = point[0];
	G[1] = point[1];

	while(--i >= 0) {
		addG(G, 0);

		if (k & (1 << i)) {
			addG1G2(G, point);
		}
	}

}

int main() {
	long point[2] = {15, 13};
	long a = 0; 
	long p = 17;
	long G[2] = {0};

	pingfanghe_kp(2, point, G);
	printf("kG = {%ld, %ld}\n", G[0], G[1]);
}
	

椭圆曲线的阶(order) 是椭圆曲线上所有EC点的个数,包含无穷远点。
椭圆曲线上点的阶: P为椭圆曲线上的点,nP=无穷远点,n取最小整数,既是P的阶;(n-1)P= -P; n为其阶。
基点(base point),用G表示,是椭圆曲线上的一个点;用倍乘KG生成循环子集上的其他点。K范围[0…r]。r为循环子集的阶,也即循环子集中的点的个数。见下文。
余因子(cofactor): 用h表示,为椭圆曲线点的个数(即椭圆曲线的阶)/基点的阶
素数域:

(p,a,b,G,n,h)

其中,p为素数,确定Fp,a和b确定椭圆曲线方程,G为基点,n为曲线的阶,h为余因子。确保秘钥空间足够大,以满足安全强度要求。
ECC(Elliptic Curve Cryptography)椭圆曲线密码详解_第7张图片
h = n / r
其中
n 曲线的阶 (曲线上所有点的个数)
h 曲线的余因子 (不相交的子群个数)
r 子群的阶 (每个子群的点的个数, 包含各个子群的无穷远点)
换句话说, 曲线上的点包含在一个或多个循环子集内. 子集的数量叫做余因子 “cofactor”. 所有循环子集的点的总和叫做曲线的阶 “order” of the curve 用 n表示. 若曲线只包含一个循环子集, h = 1. 若曲线包含许多循环子集 cofactor > 1.
cofactor = 1 secp256k1.
cofactor = 8 Curve25519.
cofactor = 4 Curve448.

cofactor = 1 时 表示只有一个循环子集,n = r. 其他的点可用KG 表示,其中K在[1…n], G 为基点。
r 与 具体的基点G相关,通过G获得,可能和曲线的阶不相等(cofactor > 1时 ),r定义了所有这个曲线下的私钥数量。
曲线的循环子集上有很多基点,选择其中之一生成整个子群。但是不同的基点生成的循环子群的阶大小不一样。也即有些点生成的群的阶很小,即包含的曲线点少,安全强度低。h > 1时,不同的基点产生不同的循环子群,所含点的数量不同,也就是选择了一个基点,相当于选择了曲线上的一个点子集

实例:
y2 ≡ x3 + 7 mod 17
基点G = {15, 13} n = 18, h =1
曲线具有17个正常的EC point,和一个无穷点。见上面的图示。
若 G ={5, 9},则只能生成3个EC point {5, 8}, {5, 9} and infinity
Generator Point - Example
At the above example (the EC over finite field y2 ≡ x3 + 7 mod 17), if we take the point G = {15, 13} as generator, any other point from the curve can be obtained by multiplying G by some integer in the range [1…18]. Thus the order of this EC is n = 18 and its cofactor h = 1.
Note that the curve has 17 normal EC points (shown at the above figures) + one special “point at infinity”, all staying in a single subgroup, and the curve order is 18 (not 17).
注意到,上面曲线的阶 n = 18,不是素数。不同的基点可能产生不同的循环子集,子集的阶不同。

有限域p上的ECC曲线的基点G、私钥k (整数)、公钥P (点)

非对称 (快速乘,反向难题) 叫做ECDLP ( Elliptic Curve Discrete Logarithm Problem).

公钥K的压缩
P {x, y} ==> C {x, odd/even)
解压:
y1 = mod_sqrt(x^3 + ax + b, p)
y2 = - mod_sqrt(x^3 + ax + b, p) + p

椭圆曲线有不同的表达形式,它们是等价的(birationally equivalent (isomorphic))
Weierstrass 曲线:
y^2 = x ^ 3 + ax + b
Weierstrass 曲线在 ECC的例子:secp256k1, y^2 = x ^3 + 7
Montgomery 曲线:
By^2 = x ^ 3 + Ax ^ 2 + x
Montgomery 曲线在 ECC 例子Curve25519, y^2 = x ^ 3 + 486662x ^ 2 + x
Edwards 曲线:
x^2 + y ^2 = 1 + d * x ^ 2 * y ^2
Edwards 曲线在 ECC 的例子 Curve448, x ^2 + y ^2 = 1 - 39081 x ^2 *y ^2

图示例:
if d = 300, Edwards 曲线 x ^2 + y ^2 = 1 + 300 * x ^2 * y ^2 如下:
ECC(Elliptic Curve Cryptography)椭圆曲线密码详解_第8张图片
Curve25519, X25519 and Ed25519
y2 = x3 + 486662x2 + x
在有限素数域 p, p = 2255 - 19 (曲线是 255-bit).
Curve25519 包含所有的点{x, y} ,x,y为整数坐标, 由下式定义:
y2 ≡ x3 + 486662x2 + x (mod 2255 - 19)

Curve25519 ,阶 n = 2252 + 0x14def9dea2f79cd65812631a5cf5d3ed ; cofactor h = 8 ;提供125.8-bit 安全强度 私钥长度 251 bits ,通常编码为 256-bit 整数 (32 bytes, 64 hex digits). 公钥也编码为 256-bit 整数(255-bit y-coordinate + 1-bit x-coordinate) .

基于 Curve25519 , ECDH , 叫作X25519 ,以及数字签名算法, 叫作Ed25519, 基于EdDSA 算法. 注意 X25519 and Ed25519 对EC 点使用不同的编码, 不直接兼容,需要转换。

Curve448, X448 and Ed448
T Curve448 (Curve448-Goldilocks) 是 untwisted Edwards 曲线,
x ^2 + y ^2 = 1 - 39081 * x ^2 * y^2
在有限素数域 p, p = 2^448 - 2 ^ 224 - 1. It has order of n = 2 ^ 446 - 0x8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d , cofactor h = 4.
Curve448 提供~ 224-bit 安全. Curve448 私钥长度 446 bits 通常编码为 448-bit 整数(56 bytes, 112 hex digits). 公钥编码为 448-bit 整数.
Curve448适合于 ECDH 秘钥交换 ( X448) ,快速签名(EdDSA 算法, 叫作 Ed448 or edwards448). X448 和 Ed448 对 EC points采用不同的编码。
Curve448 比Curve25519 慢3倍,使用 更长的秘钥长度和签名长度。

你可能感兴趣的:(ecc,密码学)