重点:ElGamal既能够加密,也能够用来签名。两者虽然过程很像,但并不是同一件事。例如:
https://blog.csdn.net/boksic/article/details/7014386
这个展示了很多原理,也介绍了加密与解密过程的实现,算是比较直接的。
而 http://blog.sina.com.cn/s/blog_5b5ed0720100atsy.htm 和 https://www.cnblogs.com/math/p/discrete-log.html 则是对ElGamal算法的依靠:离散对数问题进行了深入的探究。可以选看。
在我们实现该算法的时候会遇到大量的幂运算,模运算的混合运算公式,例如: 如果 b太大,则会出现Int 类型装不下的情况。因此可以结合 https://www.cnblogs.com/juruohx/p/7787415.html 这里介绍的模运算公式 (a + b) % p = (a % p + b % p) % p 来写出如下代码来进行计算:
private int calc_BigNum(int c1,int c2,int p)
{
//递归方法
//if (c2 == 1)
//{
// return Convert.ToInt32(c1 % p);
//}
//else
//{
// return Convert.ToInt32(((c1 % p) * calc_BigNum(c1, c2 - 1, p)) % p);
//}
//非递归方法
if (c2 == 0)
{
return 1;
}
List result = new List();
while (c2>0)
{
result.Add(Convert.ToInt32(c1 % p));
c2 -= 1;
}
int value = Convert.ToInt32(result[0] % p);
for (int i = 1; i < result.Count; i++)
{
value *= Convert.ToInt32(result[i] % p);
value = Convert.ToInt32(value % p);
}
return Convert.ToInt32(value % p);
}
这样就能够解决了(不推荐递归的算法,容易溢出)
最后,关于讲的最好的和最全面的应该是:https://www.jiamisoft.com/blog/20564-elgamal.html
但是这一句:
再用扩展 Euclidean 算法对下面方程求解b:
M = xa + kb ( mod p - 1 ) ,签名就是( a, b )。随机数k须丢弃。
则是没有解释怎么在已知m,x,a,k,p的情况下求b。我自己写了下面的方法来求:
private int calc_c2(int m,int x , int c1 , int k, int p)
{
while (true)
{
if(m-c1*x > 0 && Convert.ToInt32((m - c1 * x) % k) == 0)
{
int c2 = (m - c1*x) / k;
return c2;
}
else
{
m += p - 1;
}
}
}
因为我和该文章的一些变量名没有相同,所以看起来很乱,在我这个代码中,该方程是这样写的:m = x*c1 + k*c2 mod (p-1)
就辛苦你们这些读者了(●ˇ∀ˇ●)
附:如果有人需要有求本原元的代码,下面的代码希望对你有用
#include
#include
#include
#include
using namespace std;
int P;
const int NUM = 32170;
int prime[NUM/4];
bool f[NUM];
int pNum = 0;
void getPrime()//线性筛选素数
{
for (int i = 2; i < NUM; ++ i)
{
if (!f[i])
{
f[i] = 1;
prime[pNum++] = i;
}
for (int j = 0; j < pNum && i*prime[j] < NUM; ++ j)
{
f[i*prime[j]] = 1;
if (i%prime[j] == 0)
{
break;
}
}
}
}
__int64 getProduct(int a,int b,int P)//快速求次幂mod
{
__int64 ans = 1;
__int64 tmp = a;
while (b)
{
if (b&1)
{
ans = ans*tmp%P;
}
tmp = tmp*tmp%P;
b>>=1;
}
return ans;
}
bool judge(int num)//求num的所有的质因子
{
int elem[1000];
int elemNum = 0;
int k = P - 1;
for (int i = 0; i < pNum; ++ i)
{
bool flag = false;
while (!(k%prime[i]))
{
flag = true;
k /= prime[i];
}
if (flag)
{
elem[elemNum ++] = prime[i];
}
if (k==1)
{
break;
}
if (k/prime[i]> P)
{
for (int i = 2;;++i)
{
if (judge(i) && i