椭圆曲线上的加密算法——MV算法的具体实现
密码学实验课老师要求我们使用大数运算库实现椭圆曲线上的MV算法。最开始老师要求很笼统,什么多余的要求也没说,之前我们做过一个小数MV算法的实现,直观感觉就是把程序中的数据类型改一改,调一调就行了…越往后做才发现大模数下的椭圆曲线算法没有想象的那么简单
1.椭圆曲线概述
这部分先鸽了
推荐大家阅读椭圆曲线密码学原理分析这篇博客,写的非常详尽,里面也有椭圆曲线在密码学的应用
2.MV算法流程
MV算法全称是Menezes-Vanstone公钥密码体制,顾名思义,是由Menezes和Vanstone两人提出的
应该没有人关心吧
MV算法是ElGamal
公钥加密算法的变种,大概就是ElGamal
在椭圆曲线上的一种表现形式,两者的核心是一样的。
我们学校使用的这本密码学课本对MV的具体实现做作了详细的描述具体的算法实现因为临近期末,鸽了。。
3.miracl库下的椭圆曲线方程常用函数
此处参考了博客miracl库下椭圆曲线方程常用函数使用入门
1)椭圆曲线方程初始化
void ecurve_init(big A,big B,big p,type);
其中A,B,P为椭圆曲线 y 2 = x 3 + a x + b y^2=x^3+ax+b y2=x3+ax+b(其中 4 a 2 + 27 b ≠ 0 4a^2+27b\neq0 4a2+27b=0)
2)初始化点
epoint* epoint_init()
当定义 e p o i n t epoint epoint后需要使用这个函数初始化
3)点乘
void ecurve_mult(big k,epoint* G,epoint *P)
返回值为 P = k G P=kG P=kG( P , G 为 椭 圆 曲 线 上 的 点 P,G为椭圆曲线上的点 P,G为椭圆曲线上的点)
4)点的加法
void ecurve_add(epoint* P,epoint* Q)
返回值为 Q = P + Q ( 椭 圆 曲 线 上 的 加 法 运 算 ) Q=P+Q(椭圆曲线上的加法运算) Q=P+Q(椭圆曲线上的加法运算)
5)点的减法
void ecurve_sub(epoint *P,epoint *Q)
返回值为 Q = Q − P ( 椭 圆 曲 线 上 的 运 算 ) Q=Q-P(椭圆曲线上的运算) Q=Q−P(椭圆曲线上的运算)
6)比较椭圆曲线上两点是否相同
bool epoint_comp(epoint *P,epoint *Q)
比较 P P P和 Q Q Q是否相同,相同返回 t r u e true true,否则为 f a l s e false false
7)释放点内存
void epoint_free(epoint *p)
8)设置点坐标,若属于当前方程则返回True,不满足当前方程返回False
bool epoint_set(big x,big y,lsb,epoint *p)
l
s
b
lsb
lsb作为
y
y
y的最低有效位我也不知道是啥,我填0
9)从 e p o i n t epoint epoint结构体中取出点坐标赋给给x、y
int epoint_get(epoint *p,big x,big y)
10)是否为无穷远点
bool point_at_infinity(epoint *p)
4.MV算法实现具体代码
推荐使用Visual Studio并且安装miracl大数运算库执行以下代码
具体安装方法请参考其它博客其实是懒得写了
extern "C" {
#include <miracl.h>
#include <mirdef.h>
#include <stdio.h>
}
#include<stdlib.h>
#include "miracl.h"
#include<iostream>
using namespace std;
int main() {
big a, b, p, Gx, Gy,n;
FILE* fp;
epoint* G = NULL;
miracl* mip = mirsys(1000, 16);
a = mirvar(0);//a,b为椭圆曲线的两个参数
b = mirvar(0);
p = mirvar(0); //p为 256 bits的大素数
Gx = mirvar(0);//Gx,Gy为生成元的坐标
Gy = mirvar(0);
n = mirvar(0);
fp = fopen("abp.txt", "r+"); //fp指向同目录下存放的SM2算法中推荐的参数
if (fp == 0)
{
printf("文件打开失败!");
exit(1);
}
mip->IOBASE = 16;
cinnum(p, fp);
cinnum(a, fp);
cinnum(b, fp);
cinnum(n, fp);
cinnum(Gx, fp);
cinnum(Gy, fp);
fclose(fp);
char s1[1000], s2[1000];//s1,s2为明文16进制字符串
cout << "请输入明文m1:";cin >> s1;
cout << "请输入明文m2:"; cin >> s2;
big m1 = mirvar(0);//m1,m2为明文
big m2 = mirvar(0);
cinstr(m1, s1);//转化字符串为大数类型
cinstr(m2, s2);
ecurve_init(a, b, p, MR_PROJECTIVE);//建立椭圆曲线y^2=x^3+ax+b;
G = epoint_init();
epoint_set(Gx, Gy, 0, G);//G是生成元,Gx,Gy为SM2算法中推荐的参数
big d = mirvar(0);//d随机生成的,是私钥
copy(p, d);
divide(d, mirvar(2), d);
bigrand(d, d);
add(d, mirvar(2), d);
cout << "私钥d为:"; cotnum(d, stdout);
big k = mirvar(0);//k是MV算法的过程量,是随机生成的
bigrand(d, k);
add(k, mirvar(2), k);
//cout << "k="; cotnum(k, stdout);
epoint *bei ;//bei是公开加密密钥
bei = epoint_init();
ecurve_mult(d, G, bei);//bei = d*G
epoint* c0;//c0是密文
c0 = epoint_init();//椭圆曲线上点c0的初始化
ecurve_mult(k, G, c0);//c0 = k*G
epoint* k0;//k0是MV加密算法的过程量
k0 = epoint_init();
ecurve_mult(k, bei, k0);//k0 = k*bei
big k1 = mirvar(0);
big k2 = mirvar(0);
epoint_get(k0, k1, k2);//k1 = k0.x k2 = k0.y
big c1 = mirvar(0);//c1,c2都是密文
big c2 = mirvar(0);
multiply(k1, m1, c1); // c1 = k1*m1(mod p)
multiply(k2, m2, c2);// c2 = k2*m2(mod p)
divide(c1, p, p);
divide(c2, p, p);
big aa = mirvar(0), bb = mirvar(0);
epoint_get(c0, aa, bb);
cout << "密文c0的x坐标为:"; cotnum(aa, stdout);
cout << "密文c0的y坐标为:"; cotnum(bb, stdout);
cout << "密文c1为:"; cotnum(c1, stdout);
cout << "密文c2为:"; cotnum(c2, stdout);
epoint* k00;//k1是MV解密算法的过程量
k00 = epoint_init();
ecurve_mult(d, c0, k00);
epoint_get(k00, k1, k2);
big m11 = mirvar(0);//m11,m22为解密后的值
big m22 = mirvar(0);
xgcd(k1, p, k1, k1, k1);
xgcd(k2, p, k2, k2, k2);
multiply(c1, k1, m11);
multiply(c2, k2, m22);
divide(m11, p, p);
divide(m22, p, p);
cout << "解密后的值m1`为:"; cotnum(m11, stdout);
cout << "解密后的值m2`为:"; cotnum(m22, stdout);
if (!mr_compare(m1, m11) && !mr_compare(m2, m22)) {
cout << "MV算法运行成功!" << endl;
}
else {
cout << "MV算法运行失败。。。" << endl;
}
mirkill(k2);
mirkill(k1);
mirkill(m1);
mirkill(m2);
mirkill(m11);
mirkill(m22);
mirkill(k);
mirkill(d);
mirkill(a);
mirkill(b);
mirkill(p);
mirkill(Gx);
mirkill(Gy);
epoint_free(bei);
epoint_free(G);
mirexit();
return 0;
}