HEAAN库学习
版本
1、地址这是最老的一版,对应的论文CKKS17
2、在1的基础上,实现了bootstarpping技术,对应的论文
3、在2的基础上,优化,效率更高!
结构
有三个文件夹:lib、run、src
lib:存放依赖库(静态文件),需要生成静态库,具体安装和生成静态库参考:MAC上安装HEAAN库
run:里面有一个run.cpp文件,为测试文件
src:里面是主要代码文件
测试文件解读
下面主要学习测试文件(run.cpp)中的几个方法
testEncodeBatch
测试复数向量的编/解码、加/解密
void TestScheme::testEncodeBatch(long logN, long logQ, long logp, long logSlots) {
/*
* 功能:测试明文的编码和解码时间
* 参数:logN(密文维数)、logQ(最大密文模数)、logp(精度,即小数位数)、logSlots(明文插槽数,即多少个明文数能打包成一个明文多项式)
*/
cout << "!!! START TEST ENCODE BATCH !!!" << endl;
//-----------------------------------------
TimeUtils timeutils;
//初始化参数
Context context(logN, logQ);
//生成私钥
SecretKey secretKey(logN);
//生成公钥、计算密钥
Scheme scheme(secretKey, context);
//-----------------------------------------
SetNumThreads(1);
//-----------------------------------------
srand(time(NULL));
//-----------------------------------------
//随机生成复数向量(含有实部和虚部)
long slots = (1 << logSlots);
complex<double>* mvec = EvaluatorUtils::randomComplexArray(slots);
timeutils.start("Encrypt batch");
//开始加密:将复数向量编码为消息,然后使用公钥将其加密成密文
Ciphertext cipher = scheme.encrypt(mvec, slots, logp, logQ);
timeutils.stop("Encrypt batch");
timeutils.start("Decrypt batch");
//开始解密:先解密,然后解密为复数向量
complex<double>* dvec = scheme.decrypt(secretKey, cipher);
timeutils.stop("Decrypt batch");
//显示结果(成对):mval(复数向量)、dval(解密后的复数向量)、eval(误差)
StringUtils::showcompare(mvec, dvec, slots, "val");
cout << "!!! END TEST ENCODE BATCH !!!" << endl;
}
testBasic
测试复数向量的编/解码、加/解密、加/乘法
void TestScheme::testBasic(long logN, long logQ, long logp, long logSlots) {
cout << "!!! START TEST BASIC !!!" << endl;
//-----------------------------------------
TimeUtils timeutils;
Context context(logN, logQ);//参数初始化
//密钥生成
SecretKey secretKey(logN);//生成私钥
Scheme scheme(secretKey, context);//生成公钥、计算密钥
//-----------------------------------------
SetNumThreads(1);
//-----------------------------------------
srand(time(NULL));
//-----------------------------------------
long slots = (1 << logSlots);//明文槽数
//生成复数向量
complex<double>* mvec1 = EvaluatorUtils::randomComplexArray(slots);
complex<double>* mvec2 = EvaluatorUtils::randomComplexArray(slots);
complex<double>* cvec = EvaluatorUtils::randomComplexArray(slots);
//定义三个复数向量,用于存计算结果(明文)
complex<double>* mvecAdd = new complex<double>[slots];
complex<double>* mvecMult = new complex<double>[slots];
complex<double>* mvecCMult = new complex<double>[slots];
for(long i = 0; i < slots; i++) {
mvecAdd[i] = mvec1[i] + mvec2[i];
mvecMult[i] = mvec1[i] * mvec2[i];
mvecCMult[i] = mvec1[i] * cvec[i];
}
timeutils.start("Encrypt two batch");
Ciphertext cipher1 = scheme.encrypt(mvec1, slots, logp, logQ);
Ciphertext cipher2 = scheme.encrypt(mvec2, slots, logp, logQ);
timeutils.stop("Encrypt two batch");
timeutils.start("Homomorphic Addition");
Ciphertext addCipher = scheme.add(cipher1, cipher2);
timeutils.stop("Homomorphic Addition");
timeutils.start("Homomorphic Multiplication");//密文*密文呢
Ciphertext multCipher = scheme.mult(cipher1, cipher2);//乘法
scheme.reScaleByAndEqual(multCipher, logp);//重缩放
timeutils.stop("Homomorphic Multiplication");
timeutils.start("Homomorphic Multiplication");//密文*常量
Ciphertext cmultCipher = scheme.multByConstVec(cipher1, cvec, slots, logp);//乘法
scheme.reScaleByAndEqual(cmultCipher, logp);//重缩放
timeutils.stop("Homomorphic Multiplication");
timeutils.start("Decrypt batch");
complex<double>* dvecAdd = scheme.decrypt(secretKey, addCipher);
complex<double>* dvecMult = scheme.decrypt(secretKey, multCipher);
complex<double>* dvecCMult = scheme.decrypt(secretKey, cmultCipher);
timeutils.stop("Decrypt batch");
cout <<"三个复数向量A、B、C:"<<endl;
StringUtils::show(mvec1,slots);
StringUtils::show(mvec2,slots);
StringUtils::show(cvec,slots);
StringUtils::showcompare(mvecAdd, dvecAdd, slots, "add");
StringUtils::showcompare(mvecMult, dvecMult, slots, "mult");
StringUtils::showcompare(mvecCMult, dvecCMult, slots, "mult");
}
Context
参数
logN:N的对数,N是密文的维数
logQ:Q的对数,Q是最大密文模数
sigma:高斯分布的标准差
h:HWT的分布参数
N:是2的次幂,对应于环\(Z\left[ X \right]/\left( X^{N}+1 \right)\)
Nh = N/2,即明文模数
logNh = logN - 1
M = 2N
logQQ:PQ的对数
PQ = Q * Q
rotGroup:预计算的旋转组索引
ksiPows:
qpowvec:预计算2的幂
taylorCoeffsMap:预计算泰勒系数
构造函数
有两种,一种是逐个赋值,一种是快速赋值
//构造函数
Context::Context(long logN, long logQ, double sigma, long h) : logN(logN), logQ(logQ), sigma(sigma), h(h) {
init(logN, logQ, sigma, h);
}
Context::Context(const Context& o) : logN(o.logN), logQ(o.logQ), sigma(o.sigma), h(o.h) {
init(logN, logQ, sigma, h);
}
初始化
//初始化函数
void Context::init(long logN, long logQ, double sigma, long h) {
N = 1 << logN; //求逆对数
Nh = N >> 1; //除2
logNh = logN - 1;
M = N << 1; //乘2
logQQ = logQ << 1; //求对数
Q = power2_ZZ(logQ); //求逆对数
QQ = power2_ZZ(logQQ);//求逆对数
rotGroup = new long[Nh]; //按顺序存储Nh个5的倍数(模 M)
long fivePows = 1;
for (long i = 0; i < Nh; ++i) {
rotGroup[i] = fivePows;
fivePows *= 5;
fivePows %= M;
}
ksiPows = new complex<double>[M + 1];//存放的复数向量
for (long j = 0; j < M; ++j) {
double angle = 2.0 * M_PI * j / M;
ksiPows[j].real(cos(angle));//实数部分
ksiPows[j].imag(sin(angle));//虚数部分
}
ksiPows[M] = ksiPows[0];
qpowvec = new ZZ[logQQ + 1];
qpowvec[0] = ZZ(1);
for (long i = 1; i < logQQ + 1; ++i) {
qpowvec[i] = qpowvec[i - 1] << 1;
}
taylorCoeffsMap.insert(pair<string, double*>(LOGARITHM, new double[11]{0,1,-0.5,1./3,-1./4,1./5,-1./6,1./7,-1./8,1./9,-1./10}));
taylorCoeffsMap.insert(pair<string, double*>(EXPONENT, new double[11]{1,1,0.5,1./6,1./24,1./120,1./720,1./5040, 1./40320,1./362880,1./3628800}));
taylorCoeffsMap.insert(pair<string, double*>(SIGMOID, new double[11]{1./2,1./4,0,-1./48,0,1./480,0,-17./80640,0,31./1451520,0}));
}
析构函数
// 析构函数
Context::~Context() {
delete[] rotGroup;
delete[] ksiPows;
}
ZZ是什么类型,泰勒系数、如何生成复数向量的?
编码
ZZX Context::encode(complex<double>* vals, long slots, long logp) {
/*
* 功能:将复数向量编码成多项式
* 参数:vals(复数数组)、slots(数组大小)、logp(量化比特)
*/
complex<double>* uvals = new complex<double>[slots]();
long i, jdx, idx;
copy(vals, vals + slots, uvals);
ZZX mx;
mx.SetLength(N);
long gap = Nh / slots;
fftSpecialInv(uvals, slots);
for (i = 0, jdx = Nh, idx = 0; i < slots; ++i, jdx += gap, idx += gap) {
mx.rep[idx] = EvaluatorUtils::scaleUpToZZ(uvals[i].real(), logp);
mx.rep[jdx] = EvaluatorUtils::scaleUpToZZ(uvals[i].imag(), logp);
}
delete[] uvals;
return mx;
}
ZZX Context::encodeSingle(complex<double> val, long logp) {
/*
* 功能:将单个复数编码成多项式
* 参数:vals(复数向量)、logp(量化比特)
*/
ZZX mx;
mx.SetLength(N);
mx.rep[0] = EvaluatorUtils::scaleUpToZZ(val.real(), logp);
mx.rep[Nh] = EvaluatorUtils::scaleUpToZZ(val.imag(), logp);
return mx;
}
ZZX Context::encode(double* vals, long slots, long logp) {
/*
* 功能:将多个数(浮点数组)编码成多项式
* 参数:vals(浮点数组)、slots(数组大小)、logp(量化比特)
*/
complex<double>* uvals = new complex<double>[slots];
long i, jdx, idx;
for (i = 0; i < slots; ++i) {
uvals[i].real(vals[i]);
}
ZZX mx;
mx.SetLength(N);
long gap = Nh / slots;
fftSpecialInv(uvals, slots);
for (i = 0, jdx = Nh, idx = 0; i < slots; ++i, jdx += gap, idx += gap) {
mx.rep[idx] = EvaluatorUtils::scaleUpToZZ(uvals[i].real(), logp);
mx.rep[jdx] = EvaluatorUtils::scaleUpToZZ(uvals[i].imag(), logp);
}
delete[] uvals;
return mx;
}
ZZX Context::encodeSingle(double val, long logp) {
/*
* 功能:将单个数(浮点数)编码成多项式
* 参数:vals(浮点数)、logp(量化比特)
*/
ZZX mx;
mx.SetLength(N);
mx.rep[0] = EvaluatorUtils::scaleUpToZZ(val, logp);
return mx;
}
解码
complex<double>* Context::decode(ZZX& mx, long slots, long logp, long logq) {
/*
* 功能:将一个多项式解码为复数数组
* 参数:mx(一个多项式)、slots(数组大小)、logp(量化比特)、logq(模数比特)
*/
ZZ q = qpowvec[logq];
long gap = Nh / slots;
complex<double>* res = new complex<double>[slots];
ZZ tmp;
for (long i = 0, idx = 0; i < slots; ++i, idx += gap) {
rem(tmp, mx[idx], q);
if(NumBits(tmp) == logq) tmp -= q;
res[i].real(EvaluatorUtils::scaleDownToReal(tmp, logp));
rem(tmp, mx[idx + Nh], q);
if(NumBits(tmp) == logq) tmp -= q;
res[i].imag(EvaluatorUtils::scaleDownToReal(tmp, logp));
}
fftSpecial(res, slots);
return res;
}
complex<double> Context::decodeSingle(ZZX& mx, long logp, long logq, bool isComplex) {
/*
* 功能:将一个多项式解码为单个复数
* 参数:mx(一个多项式)、logp(量化比特)、logq(模数比特)、isComplex(是否解码后是复数,默认是)
*/
ZZ q = qpowvec[logq];
complex<double> res;
ZZ tmp = mx.rep[0] % q;
if(NumBits(tmp) == logq) tmp -= q;
res.real(EvaluatorUtils::scaleDownToReal(tmp, logp));
if(isComplex) {
tmp = mx.rep[Nh] % q;
if(NumBits(tmp) == logq) tmp -= q;
res.imag(EvaluatorUtils::scaleDownToReal(tmp, logp));
}
return res;
}
FFT
void Context::bitReverse(complex<double>* vals, const long size) {
/*
* 功能:求FFT的比特置换(非)
* 参数:vals(复数数组)、size(数组大小)
*/
for (long i = 1, j = 0; i < size; ++i) {
long bit = size >> 1;
for (; j >= bit; bit>>=1) {
j -= bit;
}
j += bit;
if(i < j) {
swap(vals[i], vals[j]);
}
}
}
void Context::fft(complex<double>* vals, const long size) {
/*
* 功能:计算FFT在Z_q[X] / (X^N + 1)
* 参数:vals(复数数组)、size(数组大小)
*/
bitReverse(vals, size);
for (long len = 2; len <= size; len <<= 1) {
long MoverLen = M / len;
long lenh = len >> 1;
for (long i = 0; i < size; i += len) {
for (long j = 0; j < lenh; ++j) {
long idx = j * MoverLen;
complex<double> u = vals[i + j];
complex<double> v = vals[i + j + lenh];
v *= ksiPows[idx];
vals[i + j] = u + v;
vals[i + j + lenh] = u - v;
}
}
}
}
void Context::fftInvLazy(complex<double>* vals, const long size) {
/*
* 功能:计算FFT的逆延迟
* 参数:vals(复数数组)、size(数组大小)
*/
bitReverse(vals, size);
for (long len = 2; len <= size; len <<= 1) {
long MoverLen = M / len;
long lenh = len >> 1;
for (long i = 0; i < size; i += len) {
for (long j = 0; j < lenh; ++j) {
long idx = (len - j) * MoverLen;
complex<double> u = vals[i + j];
complex<double> v = vals[i + j + lenh];
v *= ksiPows[idx];
vals[i + j] = u + v;
vals[i + j + lenh] = u - v;
}
}
}
}
void Context::fftInv(complex<double>* vals, const long size) {
/*
* 功能:计算FFT的逆在Z_q[X] / (X^N + 1)
* 参数:vals(复数数组)、size(数组大小)
*/
fftInvLazy(vals, size);
for (long i = 0; i < size; ++i) {
vals[i] /= size;
}
}
void Context::fftSpecial(complex<double>* vals, const long size) {
/*
* 功能:在编码和解密时计算特殊FFT在Z_q[X] / (X^N + 1)
* 参数:vals(复数数组)、size(数组大小)
*/
bitReverse(vals, size);
for (long len = 2; len <= size; len <<= 1) {
for (long i = 0; i < size; i += len) {
long lenh = len >> 1;
long lenq = len << 2;
for (long j = 0; j < lenh; ++j) {
long idx = ((rotGroup[j] % lenq)) * M / lenq;
complex<double> u = vals[i + j];
complex<double> v = vals[i + j + lenh];
v *= ksiPows[idx];
vals[i + j] = u + v;
vals[i + j + lenh] = u - v;
}
}
}
}
void Context::fftSpecialInvLazy(complex<double>* vals, const long size) {
/*
* 功能:在编码和解密时 计算特殊FFT逆的延迟 在Z_q[X] / (X^N + 1)
* 参数:vals(复数数组)、size(数组大小)
*/
for (long len = size; len >= 1; len >>= 1) {
for (long i = 0; i < size; i += len) {
long lenh = len >> 1;
long lenq = len << 2;
for (long j = 0; j < lenh; ++j) {
long idx = (lenq - (rotGroup[j] % lenq)) * M / lenq;
complex<double> u = vals[i + j] + vals[i + j + lenh];
complex<double> v = vals[i + j] - vals[i + j + lenh];
v *= ksiPows[idx];
vals[i + j] = u;
vals[i + j + lenh] = v;
}
}
}
bitReverse(vals, size);
}
void Context::fftSpecialInv(complex<double>* vals, const long size) {
/*
* 功能:在编码和解密时 计算特殊FFT逆 在Z_q[X] / (X^N + 1)
* 参数:vals(复数数组)、size(数组大小)
*/
fftSpecialInvLazy(vals, size);
for (long i = 0; i < size; ++i) {
vals[i] /= size;
}
}
关于FFT相关的知识,需要系统学习,后续整理出一篇文章!
Plaintext
参数
mx:一个多项式 mod X^N + 1
logp:量化比特
logq:模数比特
slots:明文槽
isComplex:是否是复数【option of Message with single real slot ?】
构造函数
Plaintext(ZZX mx = ZZX::zero(), long logp = 0, long logq = 0, long slots = 1, bool isComplex = true) : mx(mx), logp(logp), logq(logq), slots(slots), isComplex(isComplex) {}
拷贝构造函数
Plaintext(const Plaintext& o) : mx(o.mx), logp(o.logp), logq(o.logq), slots(o.slots), isComplex(o.isComplex) {}
Ciphertext
密文是一个RLWE实例(ax, bx = mx + ex - ax * sx) 在环 Z_q[X] / (X^N + 1)
参数
ax和bx:都是多项式,满足(ax, bx = mx + ex - ax * sx) 在环 Z_q[X] / (X^N + 1)
logp:?
logq:密文模数的对数
slots:密文的槽数
isComplex:?
构造函数
Ciphertext(ZZX ax = ZZX::zero(), ZZX bx = ZZX::zero(), long logp = 0, long logq = 0, long slots = 1, bool isComplex = true) : ax(ax), bx(bx), logp(logp), logq(logq), slots(slots), isComplex(isComplex) {}
拷贝构造函数
Ciphertext(const Ciphertext& o) : ax(o.ax), bx(o.bx), logp(o.logp), logq(o.logq), slots(o.slots), isComplex(o.isComplex) {}
Ring2Utils
多项式求模
void Ring2Utils::mod(ZZX& res, ZZX& p, ZZ& mod, const long degree) {
/*
* 功能:多项式求模 p,输出
* 参数:res(待求模的多项式)、p(输出结果,在Z_q[X] / (X^N + 1)上的一个多项式)、mod(大整数,模数q)、degree(多项式次数,N)
*/
res.SetLength(degree);
for (long i = 0; i < degree; ++i) {
rem(res.rep[i], p.rep[i], mod);
}
}
void Ring2Utils::modAndEqual(ZZX& p, ZZ& mod, const long degree) {
/*
* 功能:多项式求模 p,自身模
* 参数:p(待求模的多项式)、mod(大整数,模数q)、degree(多项式次数,N)
*/
for (long i = 0; i < degree; ++i) {
rem(p.rep[i], p.rep[i], mod);
}
}
多项式加法
void Ring2Utils::add(ZZX& res, ZZX& p1, ZZX& p2, ZZ& mod, const long degree) {
/*
* 功能:环Z_q[X] / (X^N + 1)中两个多项式相加,在模数下 【无输出】
* 参数:res(p1 + p2 在 Z_q[X] / (X^N + 1))、p1和p2(两个多项式)、mod(模数,q)、degree(多项式次数,N)
*/
res.SetLength(degree);
for (long i = 0; i < degree; ++i) {
AddMod(res.rep[i], p1.rep[i], p2.rep[i], mod);
}
}
ZZX Ring2Utils::add(ZZX& p1, ZZX& p2, ZZ& mod, const long degree) {
/*
* 功能:环Z_q[X] / (X^N + 1)中两个多项式相加,输出res 【有输出】
* 参数:res(输出 p1 + p2 在 Z_q[X] / (X^N + 1))、p1和p2(两个多项式)、mod(模数,q)、degree(多项式次数,N)
*/
ZZX res;
add(res, p1, p2, mod, degree);
return res;
}
void Ring2Utils::addAndEqual(ZZX& p1, ZZX& p2, ZZ& mod, const long degree) {
/*
* 功能:环Z_q[X] / (X^N + 1)中两个多项式相加,p1 -> p1 + p2 【无输出】
* 参数:、p1和p2(两个多项式)、mod(模数,q)、degree(多项式次数,N)
*/
for (long i = 0; i < degree; ++i) {
AddMod(p1.rep[i], p1.rep[i], p2.rep[i], mod);
}
}
多项式减法
void Ring2Utils::sub(ZZX& res, ZZX& p1, ZZX& p2, ZZ& mod, const long degree) {
/*
* 功能:环Z_q[X] / (X^N + 1)中两个多项式相减,在模数下 【无输出】
* 参数:res(p1 - p2 在 Z_q[X] / (X^N + 1))、p1和p2(两个多项式)、mod(模数,q)、degree(多项式次数,N)
*/
res.SetLength(degree);
for (long i = 0; i < degree; ++i) {
AddMod(res.rep[i], p1.rep[i], -p2.rep[i], mod);
}
}
ZZX Ring2Utils::sub(ZZX& p1, ZZX& p2, ZZ& mod, const long degree) {
/*
* 功能:环Z_q[X] / (X^N + 1)中两个多项式相减,输出res 【有输出】
* 参数:res(输出 p1 - p2 在 Z_q[X] / (X^N + 1))、p1和p2(两个多项式)、mod(模数,q)、degree(多项式次数,N)
*/
ZZX res;
sub(res, p1, p2, mod, degree);
return res;
}
void Ring2Utils::subAndEqual(ZZX& p1, ZZX& p2, ZZ& mod, const long degree) {
/*
* 功能:环Z_q[X] / (X^N + 1)中两个多项式相减,p1 -> p1 - p2 【无输出】
* 参数:、p1和p2(两个多项式)、mod(模数,q)、degree(多项式次数,N)
*/
for (long i = 0; i < degree; ++i) {
AddMod(p1.rep[i], p1.rep[i], -p2.rep[i], mod);
}
}
void Ring2Utils::subAndEqual2(ZZX& p1, ZZX& p2, ZZ& mod, const long degree) {
/*
* 功能:环Z_q[X] / (X^N + 1)中两个多项式相减,p2 -> p1 - p2 【无输出】
* 参数:、p1和p2(两个多项式)、mod(模数,q)、degree(多项式次数,N)
*/
for (long i = 0; i < degree; ++i) {
AddMod(p2.rep[i], p1.rep[i], -p2.rep[i], mod);
}
}
多项式乘法
void Ring2Utils::mult(ZZX& res, ZZX& p1, ZZX& p2, ZZ& mod, const long degree) {
/*
* 功能:res=p1 * p2 在 Z_q[X] / (X^N + 1)上 【无输出】
* mod(模数,q)、degree(多项式次数,N)
*/
res.SetLength(degree);
ZZX pp;
mul(pp, p1, p2);
pp.SetLength(2 * degree);
for (long i = 0; i < degree; ++i) {
rem(pp.rep[i], pp.rep[i], mod);
rem(pp.rep[i + degree], pp.rep[i + degree], mod);
SubMod(res.rep[i], pp.rep[i], pp.rep[i + degree], mod);
}
}
ZZX Ring2Utils::mult(ZZX& p1, ZZX& p2, ZZ& mod, const long degree) {
/*
* 功能:res=p1 * p2 在 Z_q[X] / (X^N + 1)上 【输出res】
* mod(模数,q)、degree(多项式次数,N)
*/
ZZX res;
mult(res, p1, p2, mod, degree);
return res;
}
void Ring2Utils::multAndEqual(ZZX& p1, ZZX& p2, ZZ& mod, const long degree) {
/*
* 功能:p1 -> p1 * p2 在 Z_q[X] / (X^N + 1)上 【无输出】
* mod(模数,q)、degree(多项式次数,N)
*/
ZZX pp;
mul(pp, p1, p2);
pp.SetLength(2 * degree);
for (long i = 0; i < degree; ++i) {
rem(pp.rep[i], pp.rep[i], mod);
rem(pp.rep[i + degree], pp.rep[i + degree], mod);
SubMod(p1.rep[i], pp.rep[i], pp.rep[i + degree], mod);
}
}
多项式平方
void Ring2Utils::square(ZZX& res, ZZX& p, ZZ& mod, const long degree) {
/*
* 功能:res=p^2 在 Z_q[X] / (X^N + 1) 【无输出】
* 参数:res和p(多项式)、mod(模数,q)、degree(多项式次数,N)
*/
res.SetLength(degree);
ZZX pp;
sqr(pp, p);
pp.SetLength(2 * degree);
for (long i = 0; i < degree; ++i) {
rem(pp.rep[i], pp.rep[i], mod);
rem(pp.rep[i + degree], pp.rep[i + degree], mod);
SubMod(res.rep[i], pp.rep[i], pp.rep[i + degree], mod);
}
}
ZZX Ring2Utils::square(ZZX& p, ZZ& mod, const long degree) {
/*
* 功能:res=p^2 在 Z_q[X] / (X^N + 1) 【输出res】
* 参数:res和p(多项式)、mod(模数,q)、degree(多项式次数,N)
*/
ZZX res;
square(res, p, mod, degree);
return res;
}
void Ring2Utils::squareAndEqual(ZZX& p, ZZ& mod, const long degree) {
/*
* 功能:p=p^2 在 Z_q[X] / (X^N + 1) 【无输出】
* 参数:p(多项式)、mod(模数,q)、degree(多项式次数,N)
*/
ZZX pp;
sqr(pp, p);
pp.SetLength(2 * degree);
for (long i = 0; i < degree; ++i) {
rem(pp.rep[i], pp.rep[i], mod);
rem(pp.rep[i + degree], pp.rep[i + degree], mod);
SubMod(p.rep[i], pp.rep[i], pp.rep[i + degree], mod);
}
}
void Ring2Utils::multByMonomial(ZZX& res, ZZX& p, const long monomialDeg, const long degree) {
/*
* 功能:res=p * X^d 在 Z_q[X] / (X^N + 1) 【无输出】
* 参数:res和p(多项式)、monomialDeg(单次项,d)、degree(多项式次数,N)
*/
long shift = monomialDeg % (2 * degree);
if(shift == 0) {
res = p;
} else {
ZZX tmpx;
tmpx.SetLength(degree);
tmpx = (shift < degree) ? p : -p;
shift %= degree;
res.SetLength(degree);
for (long i = 0; i < shift; ++i) {
res.rep[i] = -tmpx.rep[degree - shift + i];
}
for (long i = shift; i < degree; ++i) {
res.rep[i] = tmpx.rep[i - shift];
}
}
}
ZZX Ring2Utils::multByMonomial(ZZX& p, const long monomialDeg, const long degree) {
/*
* 功能:res=p * X^d 在 Z_q[X] / (X^N + 1) 【输出res】
* 参数:res和p(多项式)、monomialDeg(单次项,d)、degree(多项式次数,N)
*/
ZZX res;
multByMonomial(res, p, monomialDeg, degree);
return res;
}
void Ring2Utils::multByMonomialAndEqual(ZZX& p, const long monomialDeg, const long degree) {
/*
* 功能:多项式乘次幂,即p -> p * X^d 在 Z_q[X] / (X^N + 1) 【无输出】
* 参数:p(多项式)、monomialDeg(单次项,d)、degree(多项式次数,N)
*/
long shift = monomialDeg % (2 * degree);
if(shift == 0) {
return;
}
ZZX tmpx;
tmpx.SetLength(degree);
tmpx = (shift < degree) ? p : -p;
shift %= degree;
for (long i = 0; i < shift; ++i) {
p.rep[i] = -tmpx.rep[degree - shift + i];
}
for (long i = shift; i < degree; ++i) {
p.rep[i] = tmpx.rep[i - shift];
}
}
void Ring2Utils::multByConst(ZZX& res, ZZX& p, const ZZ& cnst, ZZ& mod, const long degree) {
/*
* 功能:多项式乘常数,即res=p * c 在 Z_q[X] / (X^N + 1) 【无输出】
* 参数:res和p(多项式)、cnst(大常数,c)、mod(模数,q)、degree(多项式次数,N)
*/
res.SetLength(degree);
for (long i = 0; i < degree; ++i) {
MulMod(res.rep[i], p.rep[i], cnst, mod);
}
}
ZZX Ring2Utils::multByConst(ZZX& p, const ZZ& cnst, ZZ& mod, const long degree) {
/*
* 功能:多项式乘常数,即res=p * c 在 Z_q[X] / (X^N + 1) 【输出res】
* 参数:res和p(多项式)、cnst(大常数,c)、mod(模数,q)、degree(多项式次数,N)
*/
ZZX res;
multByConst(res, p, cnst, mod, degree);
return res;
}
void Ring2Utils::multByConstAndEqual(ZZX& p, const ZZ& cnst, ZZ& mod, const long degree) {
/*
* 功能:多项式乘常数,即p=p * c 在 Z_q[X] / (X^N + 1) 【无输出】
* 参数:p(多项式)、cnst(大常数,c)、mod(模数,q)、degree(多项式次数,N)
*/
for (long i = 0; i < degree; ++i) {
MulMod(p.rep[i], p.rep[i], cnst, mod);
}
}
void Ring2Utils::leftShift(ZZX& res, ZZX& p, const long bits, ZZ& mod, const long degree) {
/*
* 功能:多项式乘常数,即res=p * 2^b 在 Z_q[X] / (X^N + 1) 【无输出】
* 参数:res和p(多项式)、bits(级数,b)、mod(模数,q)、degree(多项式次数,N)
*/
res.SetLength(degree);
for (long i = 0; i < degree; ++i) {
LeftShift(res.rep[i], p.rep[i], bits);
rem(res.rep[i], res.rep[i], mod);
}
}
void Ring2Utils::leftShiftAndEqual(ZZX& p, const long bits, ZZ& mod, const long degree) {
/*
* 功能:多项式乘常数,即p=p * 2^b 在 Z_q[X] / (X^N + 1) 【无输出】
* 参数:p(多项式)、bits(级数,b)、mod(模数,q)、degree(多项式次数,N)
*/
for (long i = 0; i < degree; ++i) {
LeftShift(p.rep[i], p.rep[i], bits);
rem(p.rep[i], p.rep[i], mod);
}
}
void Ring2Utils::doubleAndEqual(ZZX& p, ZZ& mod, const long degree) {
/*
* 功能:多项式乘常数,即p=2p 在 Z_q[X] / (X^N + 1) 【无输出】
* 参数:p(多项式)、mod(模数,q)、degree(多项式次数,N)
*/
for (long i = 0; i < degree; ++i) {
LeftShift(p.rep[i], p.rep[i], 1);
rem(p.rep[i], p.rep[i], mod);
}
}
void Ring2Utils::rightShift(ZZX& res, ZZX& p, const long bits, const long degree) {
/*
* 功能:多项式乘常数,res=p / 2^b 在 Z_q[X] / (X^N + 1) 【无输出】
* 参数:res和p(多项式)、bits(级数,b)、degree(多项式次数,N)
*/
res.SetLength(degree);
for (long i = 0; i < degree; ++i) {
RightShift(res.rep[i], p.rep[i], bits);
}
}
void Ring2Utils::rightShiftAndEqual(ZZX& p, const long bits, const long degree) {
/*
* 功能:多项式乘常数,p -> p / 2^b 在 Z_q[X] / (X^N + 1) 【无输出】
* 参数:p(多项式)、bits(级数,b)、degree(多项式次数,N)
*/
for (long i = 0; i < degree; ++i) {
RightShift(p.rep[i], p.rep[i], bits);
}
}
多项式共轭
void Ring2Utils::conjugate(ZZX& res, ZZX& p, const long degree) {
/*
* 功能:求共轭,res=conj(p) 在 Z_q[X] / (X^N + 1) 【无输出】
* 参数:res和p(多项式)、degree(多项式次数,N)
*/
res.SetLength(degree);
res.rep[0] = p.rep[0];
for (long i = 1; i < degree; ++i) {
res.rep[i] = -p.rep[degree - i];
}
}
void Ring2Utils::conjugateAndEqual(ZZX& p, const long degree) {
/*
* 功能:求共轭,p=conj(p) 在 Z_q[X] / (X^N + 1) 【无输出】
* 参数:p(多项式)、degree(多项式次数,N)
*/
for (long i = 0; i < degree / 2; ++i) {
ZZ tmp = p.rep[i];
p.rep[i] = p.rep[degree - i];
p.rep[degree - i] = tmp;
}
p.rep[degree / 2] = -p.rep[degree / 2];
}
其他
void Ring2Utils::inpower(ZZX& res, ZZX& p, const long pow, ZZ& mod, const long degree) {
/*
* 功能:res=p(X^pow) 在 Z_q[X] / (X^N + 1) 【无输出】
* 参数:res和p(多项式)、pow(次幂)、mod(模数,q)、degree(多项式次数,N)
*/
res.kill();
res.SetLength(degree);
for (long i = 0; i < degree; ++i) {
long ipow = i * pow;
long shift = ipow % (2 * degree);
if(shift < degree) {
AddMod(res.rep[shift % degree], res.rep[shift % degree], p.rep[i], mod);
} else {
AddMod(res.rep[shift % degree], res.rep[shift % degree], -p.rep[i], mod);
}
}
}
ZZX Ring2Utils::inpower(ZZX& p, const long pow, ZZ& mod, const long degree) {
/*
* 功能:res=p(X^pow) 在 Z_q[X] / (X^N + 1) 【输出res】
* 参数:res和p(多项式)、pow(次幂)、mod(模数,q)、degree(多项式次数,N)
*/
ZZX res;
inpower(res, p, pow, mod, degree);
return res;
}
NumUtils
高斯采样
void NumUtils::sampleGauss(ZZX& res, const long size, const double stdev) {
/*
* 功能:在高斯分布中随机采样系数生成多项式
* 参数:res(随机生成的多项式)、size(多项式次数)、stdev(高斯分布的标准差)
*/
static double const Pi = 4.0 * atan(1.0);
static long const bignum = 0xfffffff;
res.SetLength(size);
for (long i = 0; i < size; i+=2) {
double r1 = (1 + RandomBnd(bignum)) / ((double)bignum + 1);
double r2 = (1 + RandomBnd(bignum)) / ((double)bignum + 1);
double theta = 2 * Pi * r1;
double rr= sqrt(-2.0 * log(r2)) * stdev;
assert(rr < 8 * stdev); // sanity-check, no more than 8 standard deviations
// Generate two Gaussians RV's, rounded to integers
long x1 = (long) floor(rr * cos(theta) + 0.5);
res.rep[i] = x1;
if(i + 1 < size) {
long x2 = (long) floor(rr * sin(theta) + 0.5);
res.rep[i + 1] = x2;
}
}
}
HWT采样
void NumUtils::sampleHWT(ZZX& res, const long size, const long h) {
/*
* 功能:随机从{-1,0,1}系数中采样生成多项式
* 参数:res(随机生成的多项式)、size(多项式次数)、h(非0的个数)
*/
res.SetLength(size);
long idx = 0;
ZZ tmp = RandomBits_ZZ(h);
while(idx < h) {
long i = RandomBnd(size);
if(res.rep[i] == 0) {
res.rep[i] = (bit(tmp, idx) == 0) ? ZZ(1) : ZZ(-1);
idx++;
}
}
}
void NumUtils::sampleZO(ZZX& res, const long size) {
/*
* 功能:随机从{-1,0,1}系数中采样生成多项式 【没有0个数的限制】
* 参数:res(随机生成的多项式)、size(多项式次数)
*/
res.SetLength(size);
ZZ tmp = RandomBits_ZZ(2 * size);
for (long i = 0; i < size; ++i) {
res.rep[i] = (bit(tmp, 2 * i) == 0) ? ZZ(0) : (bit(tmp, 2 * i + 1) == 0) ? ZZ(1) : ZZ(-1);
}
}
{0,1}采样
void NumUtils::sampleBinary(ZZX& res, const long size, const long h) {
/*
* 功能:随机从{0,1}系数中采样生成多项式
* 参数:res(随机生成的多项式)、size(多项式次数)、h(非0的个数)
*/
res.SetLength(size);
long idx = 0;
while(idx < h) {
long i = RandomBnd(size);
if(res.rep[i] == 0) {
res.rep[i] = ZZ(1);
idx++;
}
}
}
void NumUtils::sampleBinary(ZZX& res, const long size) {
/*
* 功能:随机从{0,1}系数中采样生成多项式 【没有0个数的限制】
* 参数:res(随机生成的多项式)、size(多项式次数)
*/
res.SetLength(size);
ZZ tmp = RandomBits_ZZ(size);
for (long i = 0; i < size; ++i) {
res.rep[i] = (bit(tmp, i) == 0) ? ZZ(0) : ZZ(1);
}
}
[0, 2^bits-1]采样
void NumUtils::sampleUniform2(ZZX& res, const long size, const long bits) {
/*
* 功能:随机从[0, 2^bits-1]中采样系数生成多项式
* 参数:res(随机生成的多项式)、size(多项式次数)、bits(位数)
*/
res.SetLength(size);
for (long i = 0; i < size; i++) {
res.rep[i] = RandomBits_ZZ(bits);
}
}
Key
Key是RLWE的一个实例(ax, bx = mx + ex - ax * sx) 在环上 Z_q[X] / (X^N + 1);
构造函数
Key(ZZX ax = ZZX::zero(), ZZX bx = ZZX::zero()) : ax(ax), bx(bx) {}
Scheme
参数
keyMap:包含用于加密、乘法计算、共轭计算的密钥
leftRotKeyMap:包含做左旋转密钥
构造函数
Scheme::Scheme(Context& context) : context(context) {
}
Scheme::Scheme(SecretKey& secretKey, Context& context) : context(context) {
//生成公钥
addEncKey(secretKey);
//生成乘法计算密钥
addMultKey(secretKey);
};
密钥生成
void Scheme::addEncKey(SecretKey& secretKey) {
/*
* 功能:生成用于公钥(密钥存储在keyMap中)
* 参数:sx(私钥中)
*/
ZZX ex, ax, bx;
NumUtils::sampleUniform2(ax, context.N, context.logQQ);//ax([0, 2^bits-1]采样)
NumUtils::sampleGauss(ex, context.N, context.sigma);//ex(高斯分布中采样)
Ring2Utils::mult(bx, secretKey.sx, ax, context.QQ, context.N);//bx=sx*ax
Ring2Utils::sub(bx, ex, bx, context.QQ, context.N);//bx=ex-sx*ax
keyMap.insert(pair<long, Key>(ENCRYPTION, Key(ax, bx)));//公钥(ax,bx)
}
void Scheme::addMultKey(SecretKey& secretKey) {
/*
* 功能:生成用于共轭密钥(密钥存储在keyMap中)
*/
ZZX ex, ax, bx, sxsx;
Ring2Utils::mult(sxsx, secretKey.sx, secretKey.sx, context.Q, context.N);//sxsx = sx * sx
Ring2Utils::leftShiftAndEqual(sxsx, context.logQ, context.QQ, context.N);//sxsx = sxsx * 2^logQ
NumUtils::sampleUniform2(ax, context.N, context.logQQ);//ax采样于[0, 2^N-1]
NumUtils::sampleGauss(ex, context.N, context.sigma);//ex采样于高斯分布
Ring2Utils::addAndEqual(ex, sxsx, context.QQ, context.N);//ex = ex + sxsx
Ring2Utils::mult(bx, secretKey.sx, ax, context.QQ, context.N);//bx = sx * ax
Ring2Utils::sub(bx, ex, bx, context.QQ, context.N);//bx = ex - bx
keyMap.insert(pair<long, Key>(MULTIPLICATION, Key(ax, bx)));//共轭密钥(ax,bx)
}
void Scheme::addConjKey(SecretKey& secretKey) {
/*
* 功能:生成用于乘法计算的密钥(密钥存储在keyMap中)
*/
ZZX ex, ax, bx, sxconj;
Ring2Utils::conjugate(sxconj, secretKey.sx, context.N);//sxconj = conj(sx)
Ring2Utils::leftShiftAndEqual(sxconj, context.logQ, context.QQ, context.N);//sxconj = sxconj * 2^logQ
NumUtils::sampleUniform2(ax, context.N, context.logQQ);//ax采样于[0, 2^N-1]
NumUtils::sampleGauss(ex, context.N, context.sigma);//ex采样于高斯分布
Ring2Utils::addAndEqual(ex, sxconj, context.QQ, context.N);//ex = ex + sxconj
Ring2Utils::mult(bx, secretKey.sx, ax, context.QQ, context.N);//bx = sx * ax
Ring2Utils::sub(bx, ex, bx, context.QQ, context.N);//bx = ex - bx
keyMap.insert(pair<long, Key>(CONJUGATION, Key(ax, bx)));//乘法密钥(ax, bx)
}
void Scheme::addLeftRotKey(SecretKey& secretKey, long rot) {
/*
* 功能:为左旋转生成密钥(密钥存储在leftRotKeyMap中)
*/
ZZX ex, ax, bx, sxrot;
Ring2Utils::inpower(sxrot, secretKey.sx, context.rotGroup[rot], context.Q, context.N);//sxrot = sx(X^rotGroup[rot])
Ring2Utils::leftShiftAndEqual(sxrot, context.logQ, context.QQ, context.N);//sxrot = sxrot * 2^logQ
NumUtils::sampleUniform2(ax, context.N, context.logQQ);//ax采样于[0, 2^N-1]
NumUtils::sampleGauss(ex, context.N, context.sigma);//ex采样于高斯分布
Ring2Utils::addAndEqual(ex, sxrot, context.QQ, context.N);//ex = ex + sxrot
Ring2Utils::mult(bx, secretKey.sx, ax, context.QQ, context.N);//bx = sx * ax
Ring2Utils::sub(bx, ex, bx, context.QQ, context.N);//bx = ex - bx
leftRotKeyMap.insert(pair<long, Key>(rot, Key(ax, bx)));//左旋转密钥(ax, bx)
}
void Scheme::addLeftRotKeys(SecretKey& secretKey) {
/*
* 功能:生成多次(两次幂)左旋转的密钥(密钥存储在leftRotKeyMap中)
*/
for (long i = 0; i < context.logNh; ++i) {
long idx = 1 << i;
if(leftRotKeyMap.find(idx) == leftRotKeyMap.end()) {
addLeftRotKey(secretKey, idx);
}
}
}
void Scheme::addRightRotKeys(SecretKey& secretKey) {
/*
* 功能:生成多次(两次幂)右旋转的密钥(密钥存储在leftRotKeyMap中)
*/
for (long i = 0; i < context.logNh; ++i) {
long idx = context.N/2 - (1 << i);
if(leftRotKeyMap.find(idx) == leftRotKeyMap.end()) {
addLeftRotKey(secretKey, idx);
}
}
}
void Scheme::addSortKeys(SecretKey& secretKey, long size) {
/*
* 功能:生成用于排序的密钥(密钥存储在leftRotKeyMap中)
*/
for (long i = 1; i < size; ++i) {
if(leftRotKeyMap.find(i) == leftRotKeyMap.end()) {
addLeftRotKey(secretKey, i);
}
}
}
编码
Plaintext Scheme::encode(double* vals, long slots, long logp, long logq) {
/*
* 功能:使用特殊的fft逆运算将double数组编码为ZZX多项式
* 参数:vals(double数组)、slots(数组大小)、logp(?)、logq(密文模式q的对数值)
*/
ZZX mx = context.encode(vals, slots, logp + context.logQ);
return Plaintext(mx, logp, logq, slots, false);
}
Plaintext Scheme::encode(complex<double>* vals, long slots, long logp, long logq) {
/*
* 功能:使用特殊的fft逆运算将复数数组编码为ZZX多项式
* 参数:vals(复数数组)、slots(数组大小)、logp(?)、logq(密文模式q的对数值)
*/
ZZX mx = context.encode(vals, slots, logp + context.logQ);
return Plaintext(mx, logp, logq, slots, true);
}
Plaintext Scheme::encodeSingle(complex<double> val, long logp, long logq) {
/*
* 功能:使用特殊的fft逆运算将单个复数值编码为ZZX多项式
* 参数:vals(复数数组)、logp(?)、logq(密文模式q的对数值)
*/
ZZX mx = context.encodeSingle(val, logp + context.logQ);
return Plaintext(mx, logp, logq, 1, true);
}
Plaintext Scheme::encodeSingle(double val, long logp, long logq) {
/*
* 功能:使用特殊的fft逆运算将单个double数编码为ZZX多项式
* 参数:vals(复数数组)、logp(?)、logq(密文模式q的对数值)
*/
ZZX mx = context.encodeSingle(val, logp + context.logQ);
return Plaintext(mx, logp, logq, 1, false);
}
解码
complex<double>* Scheme::decode(Plaintext& msg) {
/*
* 功能:使用特殊的fft将ZZX多项式解码为复数数组
* 参数:msg(编码后的明文)
*/
return context.decode(msg.mx, msg.slots, msg.logp, msg.logq);
}
complex<double> Scheme::decodeSingle(Plaintext& msg) {
/*
* 功能:使用特殊的fft将ZZX多项式解码为单个复数
* 参数:msg(编码后的明文)
*/
return context.decodeSingle(msg.mx, msg.logp, msg.logq, msg.isComplex);
}
加密
Ciphertext Scheme::encryptMsg(Plaintext& msg) {
/*
* 功能:使用公钥将编码后的明文加密为密文
* 参数:公钥(ax,bx)
*/
ZZX ax, bx, vx, ex;
Key key = keyMap.at(ENCRYPTION);//key是一个RLWE实例
ZZ qQ = context.qpowvec[msg.logq + context.logQ];//
NumUtils::sampleZO(vx, context.N);//vx从{-1,0,1}采样
Ring2Utils::mult(ax, vx, key.ax, qQ, context.N);//ax = vx * ax
NumUtils::sampleGauss(ex, context.N, context.sigma);//ex从高斯采样
Ring2Utils::addAndEqual(ax, ex, qQ, context.N);//ax = ax + ex
Ring2Utils::mult(bx, vx, key.bx, qQ, context.N);// bx = vx * bx
NumUtils::sampleGauss(ex, context.N, context.sigma);//ex从高斯采样
Ring2Utils::addAndEqual(bx, ex, qQ, context.N);//bx = bx + ex
Ring2Utils::addAndEqual(bx, msg.mx, qQ, context.N);//bx = bx + mx
//为什么进行这一步?进行模?
Ring2Utils::rightShiftAndEqual(ax, context.logQ, context.N);//ax = ax / 2^logQ
Ring2Utils::rightShiftAndEqual(bx, context.logQ, context.N);//bx = bx / 2^logQ
//输出密文:(ax * vx +ex , bx * vx +ex +mx)mod
return Ciphertext(ax, bx, msg.logp, msg.logq, msg.slots, msg.isComplex);
}
Ciphertext Scheme::encrypt(double* vals, long slots, long logp, long logq) {
/*
* 功能:将double数组编码为明文消息,然后使用公钥将其加密为密文
* 参数:vals(double数组)、slots(数组大小)
*/
//先编码
Plaintext msg = encode(vals, slots, logp, logq);
//后加密
return encryptMsg(msg);
}
Ciphertext Scheme::encrypt(complex<double>* vals, long slots, long logp, long logq) {
/*
* 功能:将复数数组编码为明文消息,然后使用公钥将其加密为密文
* 参数:vals(复数数组)、slots(数组大小)
*/
//先编码
Plaintext msg = encode(vals, slots, logp, logq);
//再加密
return encryptMsg(msg);
}
Ciphertext Scheme::encryptSingle(double val, long logp, long logq) {
/*
* 功能:将一个double数编码到消息中,然后使用公钥将其加密为密文
* 参数:val(一个double数)
*/
//先编码
Plaintext msg = encodeSingle(val, logp, logq);
//后加密
return encryptMsg(msg);
}
Ciphertext Scheme::encryptSingle(complex<double> val, long logp, long logq) {
/*
* 功能:将一个复数编码到消息中,然后使用公钥将其加密为密文
* 参数:val(一个复数)
*/
//先编码
Plaintext msg = encodeSingle(val, logp, logq);
//后加密
return encryptMsg(msg);
}
Ciphertext Scheme::encryptZeros(long slots, long logp, long logq) {
/*
* 功能:将一组零编码为消息,然后使用公钥将其加密为密文
* 参数:slots(数组大小)
*/
//生成零明文数组
Ciphertext czeros = encryptSingle(0.0, logp, logq);
czeros.isComplex = true;
czeros.slots = slots;
return czeros;
}
解密
Plaintext Scheme::decryptMsg(SecretKey& secretKey, Ciphertext& cipher) {
/*
* 功能:使用私钥将密文解密为明文消息
* 参数:secretKey(私钥)、cipher(密文)
*/
ZZ q = context.qpowvec[cipher.logq];
ZZX mx;
Ring2Utils::mult(mx, cipher.ax, secretKey.sx, q, context.N);//mx = ax * sx
Ring2Utils::addAndEqual(mx, cipher.bx, q, context.N);//mx = ax * sx + bx
return Plaintext(mx, cipher.logp, cipher.logq, cipher.slots, cipher.isComplex);
}
complex<double>* Scheme::decrypt(SecretKey& secretKey, Ciphertext& cipher) {
/*
* 功能:将密文解密为消息,然后将其解码为复数数组
* 参数:secretKey(私钥)、cipher(一个密文)
*/
//先解密
Plaintext msg = decryptMsg(secretKey, cipher);
//再解码
return decode(msg);
}
complex<double> Scheme::decryptSingle(SecretKey& secretKey, Ciphertext& cipher) {
/*
* 功能:将密文解密为消息,然后将其解码为单复数值
* 参数:secretKey(私钥)、cipher(一个密文)
*/
//先解密
Plaintext msg = decryptMsg(secretKey, cipher);
//再解码
return decodeSingle(msg);
}
密文求反
Ciphertext Scheme::negate(Ciphertext& cipher) {
/*
* 功能:ciphertext(-m)
* 参数:cipher(密文,ciphertext(m))
*/
return Ciphertext(-cipher.ax, -cipher.bx, cipher.logp, cipher.logq, cipher.slots, cipher.isComplex);
}
void Scheme::negateAndEqual(Ciphertext& cipher) {
/*
* 功能:ciphertext(m) = ciphertext(-m)
*/
cipher.ax = -cipher.ax;
cipher.bx = -cipher.bx;
}
密文相加
Ciphertext Scheme::add(Ciphertext& cipher1, Ciphertext& cipher2) {
/*
* 功能:ciphertext(m1 + m2)
*/
ZZ q = context.qpowvec[cipher1.logq];
ZZX ax, bx;
Ring2Utils::add(ax, cipher1.ax, cipher2.ax, q, context.N);
Ring2Utils::add(bx, cipher1.bx, cipher2.bx, q, context.N);
return Ciphertext(ax, bx, cipher1.logp, cipher1.logq, cipher1.slots, cipher1.isComplex);
}
void Scheme::addAndEqual(Ciphertext& cipher1, Ciphertext& cipher2) {
/*
* 功能:ciphertext(m1) = ciphertext(m1 + m2)
*/
ZZ q = context.qpowvec[cipher1.logq];
Ring2Utils::addAndEqual(cipher1.ax, cipher2.ax, q, context.N);
Ring2Utils::addAndEqual(cipher1.bx, cipher2.bx, q, context.N);
}
Ciphertext Scheme::addConst(Ciphertext& cipher, double cnst, long logp) {
/*
* 功能:ciphertext(m + cnst * 2^logp)
* 参数:cipher(密文,ciphertext(m))、cnst(一个double型常数)、logp(量化比特?,如果logp<0,则使用cipher.logp,否则logp)
*/
ZZ q = context.qpowvec[cipher.logq];
ZZX ax = cipher.ax;
ZZX bx = cipher.bx;
ZZ cnstZZ = logp < 0 ? EvaluatorUtils::scaleUpToZZ(cnst, cipher.logp) : EvaluatorUtils::scaleUpToZZ(cnst, logp);
AddMod(bx.rep[0], cipher.bx.rep[0], cnstZZ, q);
return Ciphertext(ax, bx, cipher.logp, cipher.logq, cipher.slots, cipher.isComplex);
}
Ciphertext Scheme::addConst(Ciphertext& cipher, RR& cnst, long logp) {
/*
* 功能:ciphertext(m + cnst * 2^logp)
* 参数:cipher(密文,ciphertext(m))、cnst(一个RR类型常量)、logp(量化比特?,如果logp<0,则使用cipher.logp,否则logp)
*/
ZZ q = context.qpowvec[cipher.logq];
ZZX ax = cipher.ax;
ZZX bx = cipher.bx;
ZZ cnstZZ = logp < 0 ? EvaluatorUtils::scaleUpToZZ(cnst, cipher.logp) : EvaluatorUtils::scaleUpToZZ(cnst, logp);
AddMod(bx.rep[0], cipher.bx.rep[0], cnstZZ, q);
return Ciphertext(ax, bx, cipher.logp, cipher.logq, cipher.slots, cipher.isComplex);
}
Ciphertext Scheme::addConst(Ciphertext& cipher, complex<double> cnst, long logp) {
/*
* 功能:ciphertext(m + cnst * 2^logp)
* 参数:cipher(密文,ciphertext(m))、cnst(一个复数型常量)、logp(量化比特?,如果logp<0,则使用cipher.logp,否则logp)
*/
ZZ q = context.qpowvec[cipher.logq];
ZZX ax = cipher.ax;
ZZX bx = cipher.bx;
ZZ cnstrZZ = logp < 0 ? EvaluatorUtils::scaleUpToZZ(cnst.real(), cipher.logp) : EvaluatorUtils::scaleUpToZZ(cnst.real(), logp);
ZZ cnstiZZ = logp < 0 ? EvaluatorUtils::scaleUpToZZ(cnst.imag(), cipher.logp) : EvaluatorUtils::scaleUpToZZ(cnst.imag(), logp);
AddMod(bx.rep[0], cipher.bx.rep[0], cnstrZZ, q);
AddMod(bx.rep[context.Nh], cipher.bx.rep[context.Nh], cnstiZZ, q);
return Ciphertext(ax, bx, cipher.logp, cipher.logq, cipher.slots, cipher.isComplex);
}
void Scheme::addConstAndEqual(Ciphertext& cipher, double cnst, long logp) {
/*
* 功能:ciphertext(m) = ciphertext(m + cnst * 2^logp)
* 参数:cipher(密文,ciphertext(m))、cnst(一个double型常量)、logp(量化比特?,如果logp<0,则使用cipher.logp,否则logp)
*/
ZZ q = context.qpowvec[cipher.logq];
ZZ cnstZZ = logp < 0 ? EvaluatorUtils::scaleUpToZZ(cnst, cipher.logp) : EvaluatorUtils::scaleUpToZZ(cnst, logp);
AddMod(cipher.bx.rep[0], cipher.bx.rep[0], cnstZZ, q);
}
void Scheme::addConstAndEqual(Ciphertext& cipher, RR& cnst, long logp) {
/*
* 功能:ciphertext(m) = ciphertext(m + cnst * 2^logp)
* 参数:cipher(密文,ciphertext(m))、cnst(一个RR型常量)、logp(量化比特?,如果logp<0,则使用cipher.logp,否则logp)
*/
ZZ q = context.qpowvec[cipher.logq];
ZZ cnstZZ = logp < 0 ? EvaluatorUtils::scaleUpToZZ(cnst, cipher.logp) : EvaluatorUtils::scaleUpToZZ(cnst, logp);
AddMod(cipher.bx.rep[0], cipher.bx.rep[0], cnstZZ, q);
}
void Scheme::addConstAndEqual(Ciphertext& cipher, complex<double> cnst, long logp) {
/*
* 功能:ciphertext(m) = ciphertext(m + cnst * 2^logp)
* 参数:cipher(密文,ciphertext(m))、cnst(一个复数型常量)、logp(量化比特?,如果logp<0,则使用cipher.logp,否则logp)
*/
ZZ q = context.qpowvec[cipher.logq];
ZZ cnstrZZ = logp < 0 ? EvaluatorUtils::scaleUpToZZ(cnst.real(), cipher.logp) : EvaluatorUtils::scaleUpToZZ(cnst.real(), logp);
ZZ cnstiZZ = logp < 0 ? EvaluatorUtils::scaleUpToZZ(cnst.imag(), cipher.logp) : EvaluatorUtils::scaleUpToZZ(cnst.imag(), logp);
AddMod(cipher.bx.rep[0], cipher.bx.rep[0], cnstrZZ, q);
AddMod(cipher.bx.rep[context.Nh], cipher.bx.rep[context.Nh], cnstiZZ, q);
}
密文相减
Ciphertext Scheme::sub(Ciphertext& cipher1, Ciphertext& cipher2) {
/*
* 功能:密文减法
* 输出:ciphertext(m1 - m2)
*/
ZZ q = context.qpowvec[cipher1.logq];
ZZX ax, bx;
Ring2Utils::sub(ax, cipher1.ax, cipher2.ax, q, context.N);
Ring2Utils::sub(bx, cipher1.bx, cipher2.bx, q, context.N);
return Ciphertext(ax, bx, cipher1.logp, cipher1.logq, cipher1.slots, cipher1.isComplex);
}
void Scheme::subAndEqual(Ciphertext& cipher1, Ciphertext& cipher2) {
/*
* 功能:密文减法
* 输出:ciphertext(m1) = ciphertext(m1 - m2)
*/
ZZ q = context.qpowvec[cipher1.logq];
Ring2Utils::subAndEqual(cipher1.ax, cipher2.ax, q, context.N);
Ring2Utils::subAndEqual(cipher1.bx, cipher2.bx, q, context.N);
}
void Scheme::subAndEqual2(Ciphertext& cipher1, Ciphertext& cipher2) {
/*
* 功能:密文减法
* 输出:ciphertext(m2) = ciphertext(m1 - m2)
*/
ZZ q = context.qpowvec[cipher1.logq];
Ring2Utils::subAndEqual2(cipher1.ax, cipher2.ax, q, context.N);
Ring2Utils::subAndEqual2(cipher1.bx, cipher2.bx, q, context.N);
}
密文乘/除虚数
Ciphertext Scheme::imult(Ciphertext& cipher) {
/*
* 功能:密文乘以i(虚单位)
* 输出:ciphertext(i * m)
*/
ZZX ax, bx;
Ring2Utils::multByMonomial(ax, cipher.ax, context.Nh, context.N);
Ring2Utils::multByMonomial(bx, cipher.bx, context.Nh, context.N);
return Ciphertext(ax, bx, cipher.logp, cipher.logq, cipher.slots, cipher.isComplex);
}
Ciphertext Scheme::idiv(Ciphertext& cipher) {
/*
* 功能:密文除于i(虚单位)
* 输出:ciphertext(m / i)
*/
ZZX ax, bx;
Ring2Utils::multByMonomial(ax, cipher.ax, 3 * context.Nh, context.N);
Ring2Utils::multByMonomial(bx, cipher.bx, 3 * context.Nh, context.N);
return Ciphertext(ax, bx, cipher.logp, cipher.logq, cipher.slots, cipher.isComplex);
}
void Scheme::imultAndEqual(Ciphertext& cipher) {
/*
* 功能:密文乘以i(虚单位)
* 输出:ciphertext(m) = ciphertext(i * m)
*/
Ring2Utils::multByMonomialAndEqual(cipher.ax, context.Nh, context.N);
Ring2Utils::multByMonomialAndEqual(cipher.bx, context.Nh, context.N);
}
void Scheme::idivAndEqual(Ciphertext& cipher) {
/*
* 功能:密文除于i(虚单位)
* 输出:ciphertext(m) = ciphertext(m / i)
*/
Ring2Utils::multByMonomialAndEqual(cipher.ax, 3 * context.Nh, context.N);
Ring2Utils::multByMonomialAndEqual(cipher.bx, 3 * context.Nh, context.N);
}
密文乘法
Ciphertext Scheme::mult(Ciphertext& cipher1, Ciphertext& cipher2) {
/*
* 功能:密文的乘法。该算法包含重线性化,为了降低噪声,我们通常需要在乘法后使用重缩放方法
* 输出:ciphertext(m1 * m2)
*/
ZZ q = context.qpowvec[cipher1.logq];
ZZ qQ = context.qpowvec[cipher1.logq + context.logQ];
ZZX axbx1, axbx2, axax, bxbx, axmult, bxmult;
Key key = keyMap.at(MULTIPLICATION);
Ring2Utils::add(axbx1, cipher1.ax, cipher1.bx, q, context.N);//axbx1 = ax1 + bx1
Ring2Utils::add(axbx2, cipher2.ax, cipher2.bx, q, context.N);//axbx2 = ax2 + bx2
Ring2Utils::multAndEqual(axbx1, axbx2, q, context.N);//axbx1 = axbx1 * axbx2
Ring2Utils::mult(axax, cipher1.ax, cipher2.ax, q, context.N);//axax = ax1 * ax2
Ring2Utils::mult(bxbx, cipher1.bx, cipher2.bx, q, context.N);//bxbx = bx1 * bx2
Ring2Utils::mult(axmult, axax, key.ax, qQ, context.N);//axmult = axax * ax
Ring2Utils::mult(bxmult, axax, key.bx, qQ, context.N);//bxmult = axax * bx
Ring2Utils::rightShiftAndEqual(axmult, context.logQ, context.N);//axmult = axmult / 2^logQ
Ring2Utils::rightShiftAndEqual(bxmult, context.logQ, context.N);//bxmult = bxmult / 2^logQ
Ring2Utils::addAndEqual(axmult, axbx1, q, context.N);//axmult = axmult + axbx1
Ring2Utils::subAndEqual(axmult, bxbx, q, context.N);//axmult = axmult - bxbx
Ring2Utils::subAndEqual(axmult, axax, q, context.N);//axmult = axmult - axax
Ring2Utils::addAndEqual(bxmult, bxbx, q, context.N);//bxmult = bxmult - bxbx
return Ciphertext(axmult, bxmult, cipher1.logp + cipher2.logp, cipher1.logq, cipher1.slots, cipher1.isComplex);
}
void Scheme::multAndEqual(Ciphertext& cipher1, Ciphertext& cipher2) {
/*
* 功能:密文的乘法。该算法包含重线性化,为了降低噪声,我们通常需要在乘法后使用重缩放方法
* 输出:ciphertext(m1) = ciphertext(m1 * m2)
*/
ZZ q = context.qpowvec[cipher1.logq];
ZZ qQ = context.qpowvec[cipher1.logq + context.logQ];
ZZX axbx1, axbx2, axax, bxbx;
Key key = keyMap.at(MULTIPLICATION);
Ring2Utils::add(axbx1, cipher1.ax, cipher1.bx, q, context.N);
Ring2Utils::add(axbx2, cipher2.ax, cipher2.bx, q, context.N);
Ring2Utils::multAndEqual(axbx1, axbx2, q, context.N);
Ring2Utils::mult(axax, cipher1.ax, cipher2.ax, q, context.N);
Ring2Utils::mult(bxbx, cipher1.bx, cipher2.bx, q, context.N);
Ring2Utils::mult(cipher1.ax, axax, key.ax, qQ, context.N);
Ring2Utils::mult(cipher1.bx, axax, key.bx, qQ, context.N);
Ring2Utils::rightShiftAndEqual(cipher1.ax, context.logQ, context.N);
Ring2Utils::rightShiftAndEqual(cipher1.bx, context.logQ, context.N);
Ring2Utils::addAndEqual(cipher1.ax, axbx1, q, context.N);
Ring2Utils::subAndEqual(cipher1.ax, bxbx, q, context.N);
Ring2Utils::subAndEqual(cipher1.ax, axax, q, context.N);
Ring2Utils::addAndEqual(cipher1.bx, bxbx, q, context.N);
cipher1.logp += cipher2.logp;
}
Ciphertext Scheme::square(Ciphertext& cipher) {
/*
* 功能:对密文进行平方运算。该算法包含重线性化,为了降低噪声,我们通常需要在乘法后使用重缩放方法
* 输出:ciphertext(m^2)
*/
ZZ q = context.qpowvec[cipher.logq];
ZZ qQ = context.qpowvec[cipher.logq + context.logQ];
ZZX axax, axbx, bxbx, bxmult, axmult;
Key key = keyMap.at(MULTIPLICATION);
Ring2Utils::square(bxbx, cipher.bx, q, context.N);
Ring2Utils::mult(axbx, cipher.ax, cipher.bx, q, context.N);
Ring2Utils::addAndEqual(axbx, axbx, q, context.N);
Ring2Utils::square(axax, cipher.ax, q, context.N);
Ring2Utils::mult(axmult, axax, key.ax, qQ, context.N);
Ring2Utils::mult(bxmult, axax, key.bx, qQ, context.N);
Ring2Utils::rightShiftAndEqual(axmult, context.logQ, context.N);
Ring2Utils::rightShiftAndEqual(bxmult, context.logQ, context.N);
Ring2Utils::addAndEqual(axmult, axbx, q, context.N);
Ring2Utils::addAndEqual(bxmult, bxbx, q, context.N);
return Ciphertext(axmult, bxmult, cipher.logp * 2, cipher.logq, cipher.slots, cipher.isComplex);
}
void Scheme::squareAndEqual(Ciphertext& cipher) {
/*
* 功能:对密文进行平方运算。该算法包含重线性化,为了降低噪声,我们通常需要在乘法后使用重缩放方法
* 输出:ciphertext(m) = ciphertext(m^2)
*/
ZZ q = context.qpowvec[cipher.logq];
ZZ qQ = context.qpowvec[cipher.logq + context.logQ];
ZZX bxbx, axbx, axax;
Key key = keyMap.at(MULTIPLICATION);
Ring2Utils::square(bxbx, cipher.bx, q, context.N);
Ring2Utils::mult(axbx, cipher.bx, cipher.ax, q, context.N);
Ring2Utils::addAndEqual(axbx, axbx, q, context.N);
Ring2Utils::square(axax, cipher.ax, q, context.N);
Ring2Utils::mult(cipher.ax, axax, key.ax, qQ, context.N);
Ring2Utils::mult(cipher.bx, axax, key.bx, qQ, context.N);
Ring2Utils::rightShiftAndEqual(cipher.ax, context.logQ, context.N);
Ring2Utils::rightShiftAndEqual(cipher.bx, context.logQ, context.N);
Ring2Utils::addAndEqual(cipher.ax, axbx, q, context.N);
Ring2Utils::addAndEqual(cipher.bx, bxbx, q, context.N);
cipher.logp *= 2;
}
Ciphertext Scheme::multByConst(Ciphertext& cipher, double cnst, long logp) {
/*
* 功能:密文乘以常数(double型)
* 输出:ciphertext(m * (cnst * 2^logp))
*/
ZZ q = context.qpowvec[cipher.logq];
ZZX ax, bx;
ZZ cnstZZ = EvaluatorUtils::scaleUpToZZ(cnst, logp);
Ring2Utils::multByConst(ax, cipher.ax, cnstZZ, q, context.N);
Ring2Utils::multByConst(bx, cipher.bx, cnstZZ, q, context.N);
return Ciphertext(ax, bx, cipher.logp + logp, cipher.logq, cipher.slots, cipher.isComplex);
}
Ciphertext Scheme::multByConst(Ciphertext& cipher, RR& cnst, long logp) {
/*
* 功能:密文乘以常数(RR型)
* 输出:ciphertext(m * (cnst * 2^logp))
*/
ZZ q = context.qpowvec[cipher.logq];
ZZX ax, bx;
ZZ cnstZZ = EvaluatorUtils::scaleUpToZZ(cnst, logp);
Ring2Utils::multByConst(ax, cipher.ax, cnstZZ, q, context.N);
Ring2Utils::multByConst(bx, cipher.bx, cnstZZ, q, context.N);
return Ciphertext(ax, bx, cipher.logp + logp, cipher.logq, cipher.slots, cipher.isComplex);
}
Ciphertext Scheme::multByConst(Ciphertext& cipher, complex<double> cnst, long logp) {
/*
* 功能:密文乘以常数(复数型)
* 输出:ciphertext(m * (cnst * 2^logp))
*/
ZZ q = context.qpowvec[cipher.logq];
ZZX axr, bxr, axi, bxi;
ZZ cnstrZZ = EvaluatorUtils::scaleUpToZZ(cnst.real(), logp);
ZZ cnstiZZ = EvaluatorUtils::scaleUpToZZ(cnst.imag(), logp);
Ring2Utils::multByMonomial(axi, cipher.ax, context.Nh, context.N);
Ring2Utils::multByMonomial(bxi, cipher.bx, context.Nh, context.N);
Ring2Utils::multByConst(axr, cipher.ax, cnstrZZ, q, context.N);
Ring2Utils::multByConst(bxr, cipher.bx, cnstrZZ, q, context.N);
Ring2Utils::multByConstAndEqual(axi, cnstiZZ, q, context.N);
Ring2Utils::multByConstAndEqual(bxi, cnstiZZ, q, context.N);
Ring2Utils::addAndEqual(axr, axi, q, context.N);
Ring2Utils::addAndEqual(bxr, bxi, q, context.N);
return Ciphertext(axr, bxr, cipher.logp + logp, cipher.logq, cipher.slots, cipher.isComplex);
}
Ciphertext Scheme::multByConstVec(Ciphertext& cipher, complex<double>* cnstVec, long slots, long logp) {
/*
* 功能:密文乘以向量(复数)
* 输出:ciphertext(m * (cnst * 2^logp))
*/
ZZX cmx = context.encode(cnstVec, slots, logp);
return multByPoly(cipher, cmx, logp);
}
Ciphertext Scheme::multByConstVec(Ciphertext& cipher, double* cnstVec, long slots, long logp) {
/*
* 功能:密文乘以向量(double型)
* 输出:ciphertext(m * (cnst * 2^logp))
*/
ZZX cmx = context.encode(cnstVec, slots, logp);
return multByPoly(cipher, cmx, logp);
}
void Scheme::multByConstAndEqual(Ciphertext& cipher, double cnst, long logp) {
/*
* 功能:密文乘以常数(double型)
* 输出:ciphertext(m) = ciphertext(m * (cnst * 2^logp))
*/
ZZ q = context.qpowvec[cipher.logq];
ZZ cnstZZ = EvaluatorUtils::scaleUpToZZ(cnst, logp);
Ring2Utils::multByConstAndEqual(cipher.ax, cnstZZ, q, context.N);
Ring2Utils::multByConstAndEqual(cipher.bx, cnstZZ, q, context.N);
cipher.logp += logp;
}
void Scheme::multByConstAndEqual(Ciphertext& cipher, RR& cnst, long logp) {
/*
* 功能:密文乘以常数(RR型)
* 输出:ciphertext(m) = ciphertext(m * (cnst * 2^logp))
*/
ZZ q = context.qpowvec[cipher.logq];
ZZ cnstZZ = EvaluatorUtils::scaleUpToZZ(cnst, logp);
Ring2Utils::multByConstAndEqual(cipher.ax, cnstZZ, q, context.N);
Ring2Utils::multByConstAndEqual(cipher.bx, cnstZZ, q, context.N);
cipher.logp += logp;
}
void Scheme::multByConstAndEqual(Ciphertext& cipher, complex<double> cnst, long logp) {
/*
* 功能:密文乘以常量(复数)
* 输出:ciphertext(m) = ciphertext(m * (cnst * 2^logp))
*/
ZZ q = context.qpowvec[cipher.logq];
ZZX axi, bxi;
ZZ cnstrZZ = EvaluatorUtils::scaleUpToZZ(cnst.real(), logp);
ZZ cnstiZZ = EvaluatorUtils::scaleUpToZZ(cnst.imag(), logp);
Ring2Utils::multByMonomial(axi, cipher.ax, context.Nh, context.N);
Ring2Utils::multByMonomial(bxi, cipher.bx, context.Nh, context.N);
Ring2Utils::multByConstAndEqual(cipher.ax, cnstrZZ, q, context.N);
Ring2Utils::multByConstAndEqual(cipher.bx, cnstrZZ, q, context.N);
Ring2Utils::multByConstAndEqual(axi, cnstiZZ, q, context.N);
Ring2Utils::multByConstAndEqual(bxi, cnstiZZ, q, context.N);
Ring2Utils::addAndEqual(cipher.ax, axi, q, context.N);
Ring2Utils::addAndEqual(cipher.bx, bxi, q, context.N);
cipher.logp += logp;
}
void Scheme::multByConstVecAndEqual(Ciphertext& cipher, complex<double>* cnstVec, long slots, long logp) {
/*
* 功能:密文乘以向量(复数)
* 输出:ciphertext(m) = ciphertext(m * (cnst * 2^logp))
*/
ZZX cmx = context.encode(cnstVec, slots, logp);
multByPolyAndEqual(cipher, cmx, logp);
}
void Scheme::multByConstVecAndEqual(Ciphertext& cipher, double* cnstVec, long slots, long logp) {
/*
* 功能:密文乘以向量(double型)
* 输出:ciphertext(m) = ciphertext(m * (cnst * 2^logp))
*/
ZZX cmx = context.encode(cnstVec, slots, logp);
multByPolyAndEqual(cipher, cmx, logp);
}
Ciphertext Scheme::multByPoly(Ciphertext& cipher, ZZX& poly, long logp) {
/*
* 功能:密文相乘(多项式),poly编码成多项式
* 输出:ciphertext(m * cnst)
*/
ZZ q = context.qpowvec[cipher.logq];
ZZX ax, bx;
Ring2Utils::mult(ax, cipher.ax, poly, q, context.N);
Ring2Utils::mult(bx, cipher.bx, poly, q, context.N);
return Ciphertext(ax, bx, cipher.logp + logp, cipher.logq, cipher.slots, cipher.isComplex);
}
void Scheme::multByPolyAndEqual(Ciphertext& cipher, ZZX& poly, long logp) {
/*
* 功能:密文相乘(多项式),poly编码成多项式
* 输出:ciphertext(m) = ciphertext(m * cnst)
*/
ZZ q = context.qpowvec[cipher.logq];
Ring2Utils::multAndEqual(cipher.ax, poly, q, context.N);
Ring2Utils::multAndEqual(cipher.bx, poly, q, context.N);
cipher.logp += logp;
}
Ciphertext Scheme::multByMonomial(Ciphertext& cipher, const long degree) {
/*
* 功能:密文(多项式)乘单项式,degree(单项式级数)
* 输出:ciphertext(m) * X^degree
*/
ZZX ax, bx;
Ring2Utils::multByMonomial(ax, cipher.ax, degree, context.N);
Ring2Utils::multByMonomial(bx, cipher.bx, degree, context.N);
return Ciphertext(ax, bx, cipher.logp, cipher.logq, cipher.slots, cipher.isComplex);
}
void Scheme::multByMonomialAndEqual(Ciphertext& cipher, const long degree) {
/*
* 功能:密文(多项式)乘单项式,degree(单项式级数)
* 输出:ciphertext(m) = ciphertext(m) * X^degree
*/
Ring2Utils::multByMonomialAndEqual(cipher.ax, degree, context.N);
Ring2Utils::multByMonomialAndEqual(cipher.bx, degree, context.N);
}
Ciphertext Scheme::multByPo2(Ciphertext& cipher, long deg) {
/*
* 功能:密文(多项式)乘2的幂,deg(2的幂)
* 输出:ciphertext(m*2^degree)
*/
ZZ q = context.qpowvec[cipher.logq];
ZZX ax, bx;
Ring2Utils::leftShift(ax, cipher.ax, deg, q, context.N);
Ring2Utils::leftShift(bx, cipher.bx, deg, q, context.N);
return Ciphertext(ax, bx, cipher.logp, cipher.logq, cipher.slots, cipher.isComplex);
}
void Scheme::multByPo2AndEqual(Ciphertext& cipher, long deg) {
/*
* 功能:密文(多项式)乘2的幂,deg(2的幂)
* 输出:ciphertext(m) -> ciphertext(m*2^degree)
*/
ZZ q = context.qpowvec[cipher.logq];
Ring2Utils::leftShiftAndEqual(cipher.ax, deg, q, context.N);
Ring2Utils::leftShiftAndEqual(cipher.bx, deg, q, context.N);
}
void Scheme::multBy2AndEqual(Ciphertext& cipher) {
/*
* 输出:ciphertext(m) -> ciphertext(2m)
*/
ZZ q = context.qpowvec[cipher.logq];
Ring2Utils::doubleAndEqual(cipher.ax, q, context.N);
Ring2Utils::doubleAndEqual(cipher.bx, q, context.N);
}
Ciphertext Scheme::divByPo2(Ciphertext& cipher, long degree) {
/*
* 功能:密文(多项式)除以2的幂
* 输出:ciphertext(m / 2^degree)
*/
ZZX ax, bx;
Ring2Utils::rightShift(ax, cipher.ax, degree, context.N);
Ring2Utils::rightShift(bx, cipher.bx, degree, context.N);
return Ciphertext(ax, bx, cipher.logp, cipher.logq - degree, cipher.slots, cipher.isComplex);
}
void Scheme::divByPo2AndEqual(Ciphertext& cipher, long degree) {
/*
* 功能:密文(多项式)除以2的幂
* 输出:ciphertext(m) = ciphertext(m / 2^degree)
*/
Ring2Utils::rightShiftAndEqual(cipher.ax, degree, context.N);
Ring2Utils::rightShiftAndEqual(cipher.bx, degree, context.N);
cipher.logq -= degree;
}
重缩放
Ciphertext Scheme::reScaleBy(Ciphertext& cipher, long bitsDown) {
/*
* 功能:重缩放,bitsDown(缩放因子)
* 输出:ciphertext(m / 2^bitsDown) with new modulus (q / 2^bitsDown)
*/
ZZX ax, bx;
Ring2Utils::rightShift(ax, cipher.ax, bitsDown, context.N);
Ring2Utils::rightShift(bx, cipher.bx, bitsDown, context.N);
return Ciphertext(ax, bx, cipher.logp - bitsDown, cipher.logq - bitsDown, cipher.slots, cipher.isComplex);
}
Ciphertext Scheme::reScaleTo(Ciphertext& cipher, long newlogq) {
/*
* 功能:重缩放,newlogq(新密文模数对数)
* 输出:ciphertext(m / 2^(logq - newlogq)) with new modulus (2^newlogq)
*/
ZZX ax, bx;
long bitsDown = cipher.logq - newlogq;
Ring2Utils::rightShift(ax, cipher.ax, bitsDown, context.N);
Ring2Utils::rightShift(bx, cipher.bx, bitsDown, context.N);
return Ciphertext(ax, bx, cipher.logp - bitsDown, newlogq, cipher.slots, cipher.isComplex);
}
void Scheme::reScaleByAndEqual(Ciphertext& cipher, long bitsDown) {
/*
* 功能:重缩放,bitsDown(缩放因子)
* 输出:ciphertext(m) -> ciphertext(m / 2^bitsDown) with new modulus (q / 2^bitsDown)
*/
Ring2Utils::rightShiftAndEqual(cipher.ax, bitsDown, context.N);
Ring2Utils::rightShiftAndEqual(cipher.bx, bitsDown, context.N);
cipher.logq -= bitsDown;
cipher.logp -= bitsDown;
}
void Scheme::reScaleToAndEqual(Ciphertext& cipher, long logq) {
/*
* 功能:重缩放,newlogq(新密文模数对数)
* 输出:ciphertext(m) -> ciphertext(m / 2^(logq - newlogq)) with new modulus (2^newlogq)
*/
long bitsDown = cipher.logq - logq;
cipher.logq = logq;
cipher.logp -= bitsDown;
Ring2Utils::rightShiftAndEqual(cipher.ax, bitsDown, context.N);
Ring2Utils::rightShiftAndEqual(cipher.bx, bitsDown, context.N);
}
模约减
Ciphertext Scheme::modDownBy(Ciphertext& cipher, long bitsDown) {
/*
* 功能:模约减,bitsDown(约减因子)
* 输出:ciphertext(m) with new modulus (q/2^bitsDown)
*/
ZZX bx, ax;
long newlogq = cipher.logq - bitsDown;
ZZ q = context.qpowvec[newlogq];
Ring2Utils::mod(ax, cipher.ax, q, context.N);
Ring2Utils::mod(bx, cipher.bx, q, context.N);
return Ciphertext(ax, bx, cipher.logp, newlogq, cipher.slots, cipher.isComplex);
}
void Scheme::modDownByAndEqual(Ciphertext& cipher, long bitsDown) {
/*
* 功能:模约减,bitsDown(约减因子)
* 输出:ciphertext(m) -> ciphertext(m) with new modulus (q/2^bitsDown)
*/
cipher.logq -= bitsDown;
ZZ q = context.qpowvec[cipher.logq];
Ring2Utils::modAndEqual(cipher.ax, q, context.N);
Ring2Utils::modAndEqual(cipher.bx, q, context.N);
}
Ciphertext Scheme::modDownTo(Ciphertext& cipher, long logq) {
/*
* 功能:模约减,logq(新模数的对数)
* 输出:ciphertext(m) with new modulus (2^newlogq)
*/
ZZX bx, ax;
ZZ q = context.qpowvec[logq];
Ring2Utils::mod(ax, cipher.ax, q, context.N);
Ring2Utils::mod(bx, cipher.bx, q, context.N);
return Ciphertext(ax, bx, cipher.logp, logq, cipher.slots);
}
void Scheme::modDownToAndEqual(Ciphertext& cipher, long logq) {
/*
* 功能:模约减,logq(新模数的对数)
* 输出:ciphertext(m) -> ciphertext(m) with new modulus (2^newlogq)
*/
cipher.logq = logq;
ZZ q = context.qpowvec[logq];
Ring2Utils::modAndEqual(cipher.ax, q, context.N);
Ring2Utils::modAndEqual(cipher.bx, q, context.N);
}
共轭密文
Ciphertext Scheme::conjugate(Ciphertext& cipher) {
/*
* 功能:计算密文的共轭密文,cipher(ciphertext(m = x + iy))
* 输出:ciphertext(x - iy)
*/
ZZ q = context.qpowvec[cipher.logq];
ZZ qQ = context.qpowvec[cipher.logq + context.logQ];
ZZX bxconj, ax, bx;
Key key = keyMap.at(CONJUGATION);
Ring2Utils::conjugate(bxconj, cipher.bx, context.N);
Ring2Utils::conjugate(bx, cipher.ax, context.N);
Ring2Utils::mult(ax, bx, key.ax, qQ, context.N);
Ring2Utils::multAndEqual(bx, key.bx, qQ, context.N);
Ring2Utils::rightShiftAndEqual(ax, context.logQ, context.N);
Ring2Utils::rightShiftAndEqual(bx, context.logQ, context.N);
Ring2Utils::addAndEqual(bx, bxconj, q, context.N);
return Ciphertext(ax, bx, cipher.logp, cipher.logq, cipher.slots, cipher.isComplex);
}
void Scheme::conjugateAndEqual(Ciphertext& cipher) {
/*
* 功能:计算密文的共轭密文,cipher(ciphertext(m = x + iy))
* 输出:ciphertext(m = x + iy) -> ciphertext(x - iy)
*/
ZZ q = context.qpowvec[cipher.logq];
ZZ qQ = context.qpowvec[cipher.logq + context.logQ];
ZZX bxconj;
Key key = keyMap.at(CONJUGATION);
Ring2Utils::conjugate(bxconj, cipher.bx, context.N);
Ring2Utils::conjugate(cipher.bx, cipher.ax, context.N);
Ring2Utils::mult(cipher.ax, cipher.bx, key.ax, qQ, context.N);
Ring2Utils::multAndEqual(cipher.bx, key.bx, qQ, context.N);
Ring2Utils::rightShiftAndEqual(cipher.ax, context.logQ, context.N);
Ring2Utils::rightShiftAndEqual(cipher.bx, context.logQ, context.N);
Ring2Utils::addAndEqual(cipher.bx, bxconj, q, context.N);
}
旋转
用在编码时生成共轭复数时
EvaluatorUtils
SerializationUtils
序列化,将随机采样的明文、生成的密钥、密文、写入文件以及读取文件
StringUtils
数据采样,包括高斯采样等
SecretKey
参数
sx:私钥
构造函数
SecretKey::SecretKey(long logN, long h) {
long N = 1 << logN; //求N
NumUtils::sampleHWT(sx, N, h);//sx采样于HWT
}
HEAAN库学习的更多相关文章
- HEAAN新版学习
本篇文章对最新版的HEAAN库进行研究,老版的介绍见 HEAAN库学习 主要参考:slide-HEAAN.pdf HEAAN介绍 HEAAN是一个支持在加密的复数数组之间进行操作的库,方案的安全性取决 ...
- python 操作exls学习之路1-openpyxl库学习
这篇要讲到的就是如何利用Python与openpyxl结合来处理xlsx表格数据.Python处理表格的库有很多,这里的openpyxl就是其中之一,但是它是处理excel2007/2010的格式,也 ...
- dlib库学习之一
dlib库学习之一 1.介绍 跨平台 C++ 通用库 Dlib 发布 ,带来了一些新特性,包括概率 CKY 解析器,使用批量同步并行计算模型来创建应用的工具,新增两个聚合算法:中国低语 (Chines ...
- python_库学习_01
一.python的库学习之 财经数据接口包 1.安装ThShare 直接pip install tushare 可能会出现缺少依赖库的情况,依次安装,大概有lxml,pandas,bs4,reques ...
- numpy, matplotlib库学习笔记
Numpy库学习笔记: 1.array() 创建数组或者转化数组 例如,把列表转化为数组 >>>Np.array([1,2,3,4,5]) Array([1,2,3,4,5]) ...
- python爬虫解析库学习
一.xpath库使用: 1.基本规则: 2.将文件转为HTML对象: html = etree.parse('./test.html', etree.HTMLParser()) result = et ...
- 【mmall】Guava库学习Collections
参考链接 Guava库学习:学习Collections(三)Sets
- muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor
目录 muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor Connector 系统函数connect 处理非阻塞connect的步骤: Connetor时序图 Accep ...
- muduo网络库学习笔记(四) 通过eventfd实现的事件通知机制
目录 muduo网络库学习笔记(四) 通过eventfd实现的事件通知机制 eventfd的使用 eventfd系统函数 使用示例 EventLoop对eventfd的封装 工作时序 runInLoo ...
随机推荐
- Linux密码文件介绍
1. 查看shadow文件内容```cat /etc/shadow```可以看到shadow文件内容,例如:```root:$1$Bg1H/4mz$X89TqH7tpi9dX1B9j5YsF.:148 ...
- windows环境jdk8下载安装与配置环境变量
1)jdk8官网下载地址 Java Downloads | Oracle 下载前需登录Oracle账号,没有的话可以用邮箱注册一个,登录之后即可进行下载. 2)jdk8安装 ①下载完成之后双击运行文件 ...
- mutation中修改state中的状态值,却报[vuex] do not mutate vuex store state outside mutation handlers.
网上百度说是在mutation外修改state中的状态值,会报下列错误,可我明明在mutations中修改的状态值,还是报错 接着百度,看到和我类似的问题,说mutations中只能用同步代码,异步用 ...
- c# - 关于位移符号 >> 和 << 的使用
1.前言 这是对二进制数据进行位移的方法 2.操作 using System; namespace ConsoleApp1.toValue { public class test1 { public ...
- spring security 自动登录 --- 心得
1.前言 仍然是使用cookie存储登录数据,但是存储的数据 由 spring security自动创建 ,当登出后自动删除cookie, 如果不登出也仍在生命周期内,关闭浏览器再打开将会自动登录,无 ...
- 微信小程序开发 --- 小白之路 --- 心得
1.前言 今天 ,发现我的饭卡不见了....悲催 ,看了一下学校的微信小程序,查了下我这饭卡的流水记录,嗯...最后出现的地方在洗澡房... 好吧,扯远了,虽然没找到,可是突发奇想 ,小程序挺方便的, ...
- ssh到localhost或127.0.0.1拒绝连接
通过ssh连接到本机报错 ssh: connect to host localhost port 22: Connection refused, 你能用ssh登录其它主机并不代表着本地有ssh服务,要 ...
- Mysql设计遵循规则
为什么要优化系统的吞吐量瓶颈往往出现在数据库的访问速度上随着应用程序的运行,数据库的中的数据会越来越多,处理时间会相应变慢数据是存放在磁盘上的,读写速度无法和内存相比 如何优化设计数据库时:数据库表. ...
- uniapp页面跳转传递参数过长
传参 url:'./photo_detail?item='+encodeURIComponent(JSON.stringify(obj)) 取参 const item = JSON.parse(dec ...
- 服务性能监控之Micrometer详解
Micrometer 为基于 JVM 的应用程序的性能监测数据收集提供了一个通用的 API,支持多种度量指标类型,这些指标可以用于观察.警报以及对应用程序当前状态做出响应. 通过添加如下依赖可以将 M ...