离散对数求解
1.实验内容
我们谈谈以下几个基本概念。
1.原根
原根是一种数学符号,设m是正整数,a是整数,若a模m的阶等于φ(m),则称a为模m的一个原根。(其中φ(m)表示m的欧拉函数)
假设一个数g是P的原根,那么g^i mod P的结果两两不同,且有 1<g<P,0<i<P,归根到底就是g^(P-1) = 1 (mod P)当且仅当指数为P-1的时候成立.(这里P是素数)。
简单来说,g^i mod p ≠ g^j mod p (p为素数),其中i≠j且i, j介于1至(p-1)之间,则g为p的原根。
2.群
基本概念可以看这里。群环域
- 上图思路是老师给出的思路,我自己实现了下,我跑了两个小时,跑了两个小时跑不出来结果,最后系统崩溃。
/*
* create hash table
*/
void createSearchTable(unordered_map<string,int>& searchTable,const mpz_class& h,const mpz_class& g,const mpz_class& p )
{
int x_max = pow(2,20);
mpz_class g_x1 = 1;
mpz_class hDivGx_1 = h;
for(int x_1 = 0;x_1<x_max;x_1++)
{
hDivGx_1 = h/g_x1 % p;
searchTable.insert(make_pair(hDivGx_1.get_str(),x_1));
g_x1 =g_x1*g;
}
cout<<"searchTable size:"<<searchTable.size()<<endl;
cout<<"create searchTable success"<<endl;
}
/*
* get result x = x0*B + x1
*/
mpz_class solve(unordered_map<string,int>& searchTable,const mpz_class& g,const mpz_class& p,int & result_x_1, int& result_x_0){
mpz_class result("0",10);
int x_0;
int x_max = pow(2,20);
//计算g**B
mpz_class gB = 1;
for(int i = 0; i < x_max; i++) {
gB = gB *g%p;
}
mpz_class gbx = 1;
for(int x_0 =0;x_0<x_max;x_0++)
{
gbx = gbx * gB %p;
auto it = searchTable.find(gbx.get_str());
if(it!=searchTable.end()){
cout<<"find x"<<endl;
result = it->second + x_0*pow(2,20);
result_x_1 = it->second;
result_x_0 = x_0;
break;
}
}
return result;
}
2.转换思路
我测试了下计算时间主要用于$g^{x1}$的逆元就算,主要在这一步代码
hDivGx_1 = h/g_x1 % p;
g_x1 =g_x1*g;
我记得在《区块链》这门课上好像讲到过这个内容,后面我查了下资料,发现这里面是存在小技巧的。
上图给的思路是
\[x = x0B + x1 其中B =2^{20} 0\leq x0,x1\leq 2^{20}-1
\]
当两边同时除以x1时候,需要求\(g^{x1}\)的逆元\(g^{-x1}\),
那么就需要重新思考这个问题。我们假设 \(x = x0B - x1 其中B =2^{20} 0\leq x1\leq 2^{20}-1 0\leq x0\leq 2^{20}+1\),这时候式子就变成了了.
\[h*g^{x1} = g^{x0*B}
\]
这时候就不需要求逆元了。
那么我们重新更换代码吧。
/*
* create hash table
*/
void createSearchTable(unordered_map<string,int>& searchTable,const mpz_class& h,const mpz_class& g,const mpz_class& p )
{
int x_max = pow(2,20);
mpz_class g_x1 = 1;
mpz_class hDivGx_1 = h;
for(int x_1 = 0;x_1<x_max;x_1++)
{
if(x_1 == 0){
hDivGx_1 = hDivGx_1%p;
searchTable.insert(make_pair(hDivGx_1.get_str(),x_1));
}
else{
hDivGx_1 = hDivGx_1*g % p;
searchTable.insert(make_pair(hDivGx_1.get_str(),x_1));
}
}
cout<<"searchTable size:"<<searchTable.size()<<endl;
cout<<"create searchTable success"<<endl;
}
/*
* get result x = x0*B - x1
*/
mpz_class solve(unordered_map<string,int>& searchTable,const mpz_class& g,const mpz_class& p,int & result_x_1, int& result_x_0){
mpz_class result("0",10);
int x_0;
int x_max = pow(2,20);
//计算g**B
mpz_class gB = 1;
for(int i = 0; i < x_max; i++) {
gB = gB *g%p;
}
mpz_class gbx = 1;
for(int x_0 =0;x_0<x_max+1;x_0++)
{
auto it = searchTable.find(gbx.get_str());
if(it!=searchTable.end()){
cout<<"find x"<<endl;
result = x_0*pow(2,20) - it->second;
result_x_1 = it->second;
result_x_0 = x_0;
break;
}
gbx = gbx * gB %p;
}
return result;
}
运行结果
附
模数的运算规则