思路
两种构造函数,一种是传入p和q的,一种是没有传参的,p和q靠程序生成。
得到p和q之后,设置密钥相关变量,n=p*q、lambda=lcm(p-1,q-1),对于长度相等的p和q来说,使用g=n+1可以快速生成密钥。
在生成密钥的过程中,通过查阅资料,有些资料上私钥为两部分,lambda和mu,mu可有lambda、g和n在后续解密过程中算出
结果
代码
main.cpp
#include <iostream>
#include "Paillier.h"
using namespace std;
using namespace NTL;
void test(Paillier p,ZZ m)
{
cout << "public key: (" << p.getN()<< ", "<< p.getG() << ")" << endl;
cout << "private key: "<<p.getLam()<< endl;
cout << "message: "<< m << endl;
ZZ c = p.encrypt(m); //加密
ZZ em = p.decrypt(c);
cout << "\nencrypt: "<< c << endl;
cout << "decrypt: "<< em << endl; //解密
if(em == m)
cout<<"\nsucess!"<<endl;
else
cout<<"\nwrong!"<<endl;
cout<<"-------------------------"<<endl;
}
int main(int argc, char** argv) {
ZZ p = ZZ(43), q = ZZ(41);
ZZ m = ZZ(12);//加密信息
// cout<<"please input p q m: ";
// cin>>p>>q>>m; //输入
Paillier p1 = Paillier(p, q);
test(p1,m);
Paillier p2 = Paillier();
test(p2,m);
return 0;
}
Paillier.h
#include <NTL/ZZ.h>
#include <NTL/ZZ_pXFactoring.h>
using namespace NTL;
class Paillier {
public:
Paillier();
Paillier(ZZ, ZZ);
void createPQ();
void init();
void createG();
ZZ L(ZZ);
ZZ getRandom(); //产生随机数
ZZ encrypt(ZZ); //加密
ZZ decrypt(ZZ); //解密
ZZ getP();
ZZ getQ();
ZZ getN();
ZZ getG();
ZZ getLam();
private:
ZZ p;
ZZ q;
ZZ n;
ZZ g;
ZZ lambda;
// ZZ mu; //本来作为私钥一部分,可又lambda、g和n求得
};
Paillier.cpp
#include "Paillier.h"
using namespace std;
using namespace NTL;
Paillier::Paillier()
{
createPQ();
// cout<<"P :"<<p<<"\tQ:"<<q<<endl;
init();
}
Paillier::Paillier(ZZ p, ZZ q)
{
this->p = p;
this->q = q;
init();
}
void Paillier::init() //初始化,生成密钥
{
n = p * q;
lambda = ((p - 1) * (q - 1)) / GCD(p - 1, q - 1); //lcm
createG();
// g = n + 1; //pq两个质数长度相同的情况下,可以快速生成密钥
}
void Paillier::createPQ() //产生两个大素数 长度相等
{
long length = 32; //长度bit
while (true)
{
p = GenPrime_ZZ(length, 80);
q = GenPrime_ZZ(length, 80);
while (p == q)
{
q = GenPrime_ZZ(length, 80);
}
if (GCD(p * q, (p - 1) * (q - 1)) == 1)
return;
}
}
// 产生g
void Paillier::createG()
{
while (1)
{
g = RandomBnd(n * n);
if (g <= 0)
continue;
if (GCD(L(PowerMod(g, lambda, n * n)), n) == 1)
return;
}
}
ZZ Paillier::L(ZZ mu)
{
return (mu - 1) / n;
}
ZZ Paillier::getRandom()
{
ZZ r;
while (1)
{
r = RandomBnd(n);
if (GCD(r, n) == 1)
return r;
}
}
ZZ Paillier::encrypt(ZZ m)
{
ZZ r = getRandom(); //随机数
// ZZ r=ZZ(131); //测试用例
return (PowerMod(g, m, n * n) * PowerMod(r, n, n * n)) % (n * n);
}
ZZ Paillier::decrypt(ZZ c)
{
ZZ mu = InvMod(L(PowerMod(g, lambda, n * n)), n); //mu 在有的文献中,mu作为私钥的一部分
return (L(PowerMod(c, lambda, n * n)) * mu) % n;
// return (L(PowerMod(c, lambda, n * n)) * InvMod(lambda, n)) % n; //如果g=n+1 可用这种简便方法
}
ZZ Paillier::getLam() {
return lambda;
}
ZZ Paillier::getP() {
return p;
}
ZZ Paillier::getQ() {
return q;
}
ZZ Paillier::getN() {
return n;
}
ZZ Paillier::getG() {
return g;
}