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;
}
運行結果
附
模數的運算規則