本文主要学习HEAAN同态库,选择最老的一版:地址,最新版在:位置,HEAAN是CKKS17论文的主要代码复现。

版本

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库学习的更多相关文章

  1. HEAAN新版学习

    本篇文章对最新版的HEAAN库进行研究,老版的介绍见 HEAAN库学习 主要参考:slide-HEAAN.pdf HEAAN介绍 HEAAN是一个支持在加密的复数数组之间进行操作的库,方案的安全性取决 ...

  2. python 操作exls学习之路1-openpyxl库学习

    这篇要讲到的就是如何利用Python与openpyxl结合来处理xlsx表格数据.Python处理表格的库有很多,这里的openpyxl就是其中之一,但是它是处理excel2007/2010的格式,也 ...

  3. dlib库学习之一

    dlib库学习之一 1.介绍 跨平台 C++ 通用库 Dlib 发布 ,带来了一些新特性,包括概率 CKY 解析器,使用批量同步并行计算模型来创建应用的工具,新增两个聚合算法:中国低语 (Chines ...

  4. python_库学习_01

    一.python的库学习之 财经数据接口包 1.安装ThShare 直接pip install tushare 可能会出现缺少依赖库的情况,依次安装,大概有lxml,pandas,bs4,reques ...

  5. numpy, matplotlib库学习笔记

    Numpy库学习笔记: 1.array()   创建数组或者转化数组 例如,把列表转化为数组 >>>Np.array([1,2,3,4,5]) Array([1,2,3,4,5]) ...

  6. python爬虫解析库学习

    一.xpath库使用: 1.基本规则: 2.将文件转为HTML对象: html = etree.parse('./test.html', etree.HTMLParser()) result = et ...

  7. 【mmall】Guava库学习Collections

    参考链接 Guava库学习:学习Collections(三)Sets

  8. muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor

    目录 muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor Connector 系统函数connect 处理非阻塞connect的步骤: Connetor时序图 Accep ...

  9. muduo网络库学习笔记(四) 通过eventfd实现的事件通知机制

    目录 muduo网络库学习笔记(四) 通过eventfd实现的事件通知机制 eventfd的使用 eventfd系统函数 使用示例 EventLoop对eventfd的封装 工作时序 runInLoo ...

随机推荐

  1. Microsoft HoloLens 开发(2): 运行Hello World

    1.下载 MixedRealityToolkit-Unity (混合现实工具包) 什么是 MixedRealityToolkit-Unity ? 一个脚本和组件的集合,加速针对微软全息和Windows ...

  2. 初识python: 类练习 - 随机数生成

    1.提取指定值之间的指定个数的随机整数. 2.继承生成随机数的类,打印"坐标". 生成随机数类: import random class GetRadndom(object): ' ...

  3. Flask_获取请求信息(三)

    引用request的方法: from flask import request 与Django不同的是,flask是不需要将request对象作为第一个参数传入视图函数,他的request对象是来自于 ...

  4. java POJO中 Integer 和 int 的不同,用int还是用Integer

    https://www.jianshu.com/p/ff535284916f [int和Integer的区别] int是java提供的8种原始类型之一,java为每个原始类型提供了封装类,Intege ...

  5. js获取设备公网ip + 服务器根据公网ip 获取IP信息

    1.前言 本来呢,想实现js定位功能,最少定位到城市,一开始,使用的是搜狐的api直接获取数据,可是,有时候搜狐不可靠,只能得到 公网ip,其他信息无用,就像这样 2.既然这样,还不如我自己请求自己的 ...

  6. vue3.0+vite+ts项目搭建-分环境打包(四)

    分环境打包配置 新建.env.dev(或者.env) VITE_NODE_ENV = 'dev' VITE_HOST = 'http://local.host.com' 执行yarn dev ,控制台 ...

  7. TensorRT 开始

    TensorRT 是 NVIDIA 自家的高性能推理库,其 Getting Started 列出了各资料入口,如下: 本文基于当前的 TensorRT 8.2 版本,将一步步介绍从安装,直到加速推理自 ...

  8. Android官方文档翻译 十八 4.2Pausing and Resuming an Activity

    Pausing and Resuming an Activity 暂停和恢复一个activity This lesson teaches you to 这节课教给你 Pause Your Activi ...

  9. 微服务架构 | 3.3 Apache Zookeeper 注册中心

    @ 目录 前言 1. Zookeeper 基础知识 1.1 Zookeeper 是什么 1.2 Zookeeper 的数据结构 1.3 Watcher 机制 1.4 常见应用场景分析 1.5 Zook ...

  10. actf2020 exec

    actf2020 exec 1.根据提示,ping一个127.0.0.1,有回显,ls一下发现index.php 3.方向找错了,绕了一大圈,还cat了index.php也没发现什么 最后没招了,回原 ...