HEAAN库学习

本文主要学习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;
}

testEncodeSingle#

测试单个复数的编码、加密、解密、解码

void TestScheme::testEncodeSingle(long logN, long logQ, long logp) {
	cout << "!!! START TEST ENCODE SINGLE !!!" << endl;
	//-----------------------------------------
	TimeUtils timeutils;
	Context context(logN, logQ);
	SecretKey secretKey(logN);
	Scheme scheme(secretKey, context);
	//-----------------------------------------
	srand(time(NULL));
	//-----------------------------------------
    //生成单个复数
	complex<double> mval = EvaluatorUtils::randomComplex();

	timeutils.start("Encrypt Single");
    //加密(编码)
	Ciphertext cipher = scheme.encryptSingle(mval, logp, logQ);
	timeutils.stop("Encrypt Single");

	timeutils.start("Decrypt Single");
    //解密(解码)
	complex<double> dval = scheme.decryptSingle(secretKey, cipher);
	timeutils.stop("Decrypt Single");

	StringUtils::showcompare(mval, dval, "val");

	cout << "!!! END TEST ENCODE SINGLE !!!" << endl;
}

testimultBatch#

测试复数乘以虚单位(i)

void TestScheme::testimultBatch(long logN, long logQ, long logp, long logSlots) {
	cout << "!!! START TEST i MULTIPLICATION BATCH !!!" << endl;
	TimeUtils timeutils;
	Context context(logN, logQ);
	SecretKey secretKey(logN);
	Scheme scheme(secretKey, context);
	//-----------------------------------------
	srand(time(NULL));
	//-----------------------------------------
	long slots = (1 << logSlots);
    //随机生成一个复数向量mvec
	complex<double>* mvec = EvaluatorUtils::randomComplexArray(slots);
	//定一个复数向量imvec
    complex<double>* imvec = new complex<double>[slots];
    //逐个将imvec赋值为mvec的共轭
	for (long i = 0; i < slots; ++i) {
		imvec[i].real(-mvec[i].imag());
		imvec[i].imag(mvec[i].real());
	}
    //加密mvec
	Ciphertext cipher = scheme.encrypt(mvec, slots, logp, logQ);

	timeutils.start("Multiplication by i batch");
    //密文成一个虚单位(i)
	Ciphertext icipher = scheme.imult(cipher);
	timeutils.stop("Multiplication by i batch");
    //解密
	complex<double>* idvec = scheme.decrypt(secretKey, icipher);

    StringUtils::show(mvec,slots);
	StringUtils::showcompare(imvec, idvec, slots, "imult");

	cout << "!!! END TEST i MULTIPLICATION 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");
}

testConjugateBatch#

测试求密文向量共轭

void TestScheme::testConjugateBatch(long logN, long logQ, long logp, long logSlots) {
	cout << "!!! START TEST CONJUGATE BATCH !!!" << endl;
	TimeUtils timeutils;
	Context context(logN, logQ);
	SecretKey secretKey(logN);
	Scheme scheme(secretKey, context);
	scheme.addConjKey(secretKey);
	//-----------------------------------------
	srand(time(NULL));
	//-----------------------------------------
	long slots = (1 << logSlots);
	complex<double>* mvec = EvaluatorUtils::randomComplexArray(slots);//随机生成一个复数数组mvec
	complex<double>* mvecconj = new complex<double>[slots];//定一个复数数组mvecconj,还未赋值
    //将mvecconj赋值为mvec的共轭
    for (long i = 0; i < slots; ++i) {
		mvecconj[i] = conj(mvec[i]);
	}
    //加密mvec
	Ciphertext cipher = scheme.encrypt(mvec, slots, logp, logQ);

	timeutils.start("Conjugate batch");
    //求密文的共轭
	Ciphertext cconj = scheme.conjugate(cipher);
	timeutils.stop("Conjugate batch");
    //解密
	complex<double>* dvecconj = scheme.decrypt(secretKey, cconj);
    //打印
	StringUtils::showcompare(mvecconj, dvecconj, slots, "conj");

	cout << "!!! END TEST CONJUGATE BATCH !!!" << endl;
}

testRotateByPo2Batch#

测试密文左旋转

void TestScheme::(long logN, long logQ, long logp, long logRotSlots, long logSlots, bool isLeft) {
	cout << "!!! START TEST ROTATE BY POWER OF 2 BATCH !!!" << endl;
	//-----------------------------------------
	TimeUtils timeutils;
	Context context(logN, logQ);
	SecretKey secretKey(logN);
	Scheme scheme(secretKey, context);
    //生成左旋密钥
	scheme.addLeftRotKeys(secretKey);
	//-----------------------------------------
	srand(time(NULL));
	//-----------------------------------------
	long slots = (1 << logSlots);
	long rotSlots = (1 << logRotSlots);//左移4位
    //随机生成一个复数向量
	complex<double>* mvec = EvaluatorUtils::randomComplexArray(slots);
    StringUtils::show(mvec,slots);
	//加密该复数向量
    Ciphertext cipher = scheme.encrypt(mvec, slots, logp, logQ);

	if(isLeft) {
		timeutils.start("Left Rotate by power of 2 batch");
        //密文左旋
		scheme.leftRotateByPo2AndEqual(cipher, logRotSlots);
		timeutils.stop("Left Rotate by power of 2 batch");
	} else {
		timeutils.start("Right Rotate by power of 2 batch");
		scheme.rightRotateByPo2AndEqual(cipher, logRotSlots);
		timeutils.stop("Right Rotate by power of 2 batch");
	}
    //解密
	complex<double>* dvec = scheme.decrypt(secretKey, cipher);

	if(isLeft) {
        //明文左旋
		EvaluatorUtils::leftRotateAndEqual(mvec, slots, rotSlots);
	} else {
		EvaluatorUtils::rightRotateAndEqual(mvec, slots, rotSlots);
	}
    //比较显示
	StringUtils::showcompare(mvec, dvec, slots, "rot");
    StringUtils::show(mvec,slots);
	//-----------------------------------------
	cout << "!!! END TEST ROTATE BY POWER OF 2 BATCH !!!" << endl;
}

testSlotsSum#

测试密文求和

Context#

参数#

logN:N的对数,N是密文的维数
logQ:Q的对数,Q是最大密文模数
sigma:高斯分布的标准差
h:HWT的分布参数
N:是2的次幂,对应于环Z[X]/(XN+1)
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
}

作者:Hang Shao

出处:https://www.cnblogs.com/pam-sh/p/15868825.html

版权:本作品采用「知识共享」许可协议进行许可。

声明:欢迎交流! 原文链接 ,如有问题,可邮件(mir_soh@163.com)咨询.

posted @   PamShao  阅读(2408)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu