HEAAN开源库源码

文章目录

  • HEAAN开源库源码
    • HEAAN.h
    • HEAAN.cpp
    • TimeUtils.h
    • TimeUtils.cpp
    • TestScheme.h
    • TestScheme.cpp
    • StringUtils.h
    • StringUtils.cpp
    • SerializationUtils.h
    • SerializationUtils.cpp
    • SecretKey.h
    • SecretKey.cpp
    • Plaintext.h
    • Plaintext.cpp
    • Params.h
    • Ciphertext.h
    • Ciphertext.cpp
    • Key.h
    • Key.cpp
    • BootContext.h
    • BootContext.cpp
    • EvaluatorUtils.h
    • EvaluatorUtils.cpp
    • Ring.h
    • Ring.cpp
    • RingMultiplier.h
    • RingMultiplier.cpp

HEAAN.h

#include "BootContext.h"
#include "Ring.h"
#include "RingMultiplier.h"
#include "Ciphertext.h"
#include "EvaluatorUtils.h"
#include "Scheme.h"
#include "SchemeAlgo.h"
#include "SecretKey.h"
#include "StringUtils.h"
#include "TimeUtils.h"
#include "SerializationUtils.h"
#include "TestScheme.h"

HEAAN.cpp

#include "TestScheme.h"using namespace heaan;int main() {//----------------------------------------------------------------------------------
//   STANDARD TESTS
//----------------------------------------------------------------------------------TestScheme::testEncrypt(1200, 30, 4);
//  TestScheme::testEncryptSingle(300, 30);
//  TestScheme::testAdd(1200, 30, 4);
//  TestScheme::testMult(1200, 30, 4);
//  TestScheme::testimult(300, 30, 4);//----------------------------------------------------------------------------------
//   ROTATE & CONJUGATE
//----------------------------------------------------------------------------------//  TestScheme::testRotateFast(1200, 30, 4, 1);
//  TestScheme::testConjugate(300, 30, 4);//----------------------------------------------------------------------------------
//   POWER & PRODUCT
//----------------------------------------------------------------------------------//  TestScheme::testPowerOf2(300, 30, 4, 4);
//  TestScheme::testPower(300, 30, 4, 13);//----------------------------------------------------------------------------------
//   FUNCTION
//----------------------------------------------------------------------------------//  TestScheme::testInverse(300, 25, 4, 6);
//  TestScheme::testLogarithm(300, 30, 4, 7);
//  TestScheme::testExponent(300, 30, 4, 7);
//  TestScheme::testSigmoid(300, 30, 4, 7);
//  TestScheme::testSigmoidLazy(300, 30, 4, 7);//----------------------------------------------------------------------------------
//   OTHER
//----------------------------------------------------------------------------------//  TestScheme::testCiphertextWriteAndRead(65, 30, 2);
//  TestScheme::testBootstrap(29, 620, 23, 3, 2);
//  TestScheme::testBootstrapSingleReal(29, 620, 23, 2);
//  TestScheme::test();return 0;
}

TimeUtils.h

C\C++ 时间函数gettimeofday,timeval,timezone小结

#ifndef HEAAN_TIMEUTILS_H_
#define HEAAN_TIMEUTILS_H_#include <iostream>struct timeval;namespace heaan {class TimeUtils {public:struct timeval startTime, stopTime;double timeElapsed;TimeUtils();void start(std::string msg);void stop(std::string msg);};}  // namespace heaan#endif

TimeUtils.cpp

#include "TimeUtils.h"#include <sys/time.h>
#include <string>using namespace std;namespace heaan {TimeUtils::TimeUtils() {timeElapsed = 0;
}void TimeUtils::start(string msg) {cout << "------------------" << endl;cout <<"Start " + msg << endl;gettimeofday(&startTime, 0);
}void TimeUtils::stop(string msg) {gettimeofday(&stopTime, 0);timeElapsed = (stopTime.tv_sec - startTime.tv_sec) * 1000.0;timeElapsed += (stopTime.tv_usec - startTime.tv_usec) / 1000.0;cout << msg +  " time = "<< timeElapsed << " ms" << endl;cout << "------------------" << endl;
}}  // namespace heaan

TestScheme.h

测试各项功能

#ifndef HEAAN_TESTSCHEME_H_
#define HEAAN_TESTSCHEME_H_namespace heaan {class TestScheme {public://----------------------------------------------------------------------------------//   STANDARD TESTS//----------------------------------------------------------------------------------static void testEncrypt(long logq, long logp, long logn);static void testEncryptBySk(long logq, long logp, long logn);static void testDecryptForShare(long logq, long logp, long logn, long logErrorBound);static void testEncryptSingle(long logq, long logp);static void testAdd(long logq, long logp, long logn);static void testMult(long logq, long logp, long logn);static void testiMult(long logq, long logp, long logn);//----------------------------------------------------------------------------------//   ROTATE & CONJUGATE TESTS//----------------------------------------------------------------------------------static void testRotateFast(long logq, long logp, long logn, long r);static void testConjugate(long logq, long logp, long logn);//----------------------------------------------------------------------------------//   POWER & PRODUCT TESTS//----------------------------------------------------------------------------------static void testPowerOf2(long logq, long logp, long logn, long logdeg);static void testPower(long logq, long logp, long logn, long degree);//----------------------------------------------------------------------------------//   FUNCTION TESTS//----------------------------------------------------------------------------------static void testInverse(long logq, long logp, long logn, long steps);static void testLogarithm(long logq, long logp, long logn, long degree);static void testExponent(long logq, long logp, long logn, long degree);static void testExponentLazy(long logq, long logp, long logn, long degree);static void testSigmoid(long logq, long logp, long logn, long degree);static void testSigmoidLazy(long logq, long logp, long logn, long degree);//----------------------------------------------------------------------------------//   BOOTSTRAPPING TESTS//----------------------------------------------------------------------------------static void testBootstrap(long logq, long logp, long logn, long logT);static void testBootstrapSingleReal(long logq, long logp, long logT);static void testWriteAndRead(long logq, long logp, long logn);};}  // namespace heaan#endif

TestScheme.cpp

/*
* Copyright (c) by CryptoLab inc.
* This program is licensed under a
* Creative Commons Attribution-NonCommercial 3.0 Unported License.
* You should have received a copy of the license along with this
* work.  If not, see <http://creativecommons.org/licenses/by-nc/3.0/>.
*/
#include "TestScheme.h"#include <NTL/BasicThreadPool.h>
#include <NTL/ZZ.h>#include "Ciphertext.h"
#include "EvaluatorUtils.h"
#include "Ring.h"
#include "Scheme.h"
#include "SchemeAlgo.h"
#include "SecretKey.h"
#include "StringUtils.h"
#include "TimeUtils.h"
#include "SerializationUtils.h"using namespace std;
using namespace NTL;namespace heaan {//----------------------------------------------------------------------------------
//   STANDARD TESTS
//----------------------------------------------------------------------------------void TestScheme::testEncrypt(long logq, long logp, long logn) {cout << "!!! START TEST ENCRYPT !!!" << endl;srand(time(NULL));SetNumThreads(8);TimeUtils timeutils;Ring ring;SecretKey secretKey(ring);Scheme scheme(secretKey, ring);long n = (1 << logn);complex<double>* mvec = EvaluatorUtils::randomComplexArray(n);Ciphertext cipher;timeutils.start("Encrypt");scheme.encrypt(cipher, mvec, n, logp, logq);timeutils.stop("Encrypt");timeutils.start("Decrypt");complex<double>* dvec = scheme.decrypt(secretKey, cipher);timeutils.stop("Decrypt");StringUtils::compare(mvec, dvec, n, "val");cout << "!!! END TEST ENCRYPT !!!" << endl;
}void TestScheme::testEncryptBySk(long logq, long logp, long logn) {cout << "!!! START TEST ENCRYPT by SK !!!" << endl;srand(time(NULL));SetNumThreads(8);TimeUtils timeutils;Ring ring;SecretKey secretKey(ring);Scheme scheme(secretKey, ring);long n = (1 << logn);complex<double>* mvec = EvaluatorUtils::randomComplexArray(n);Ciphertext cipher;timeutils.start("Encrypt by sk");scheme.encryptBySk(cipher, secretKey, mvec, n, logp, logq);timeutils.stop("Encrypt by sk");timeutils.start("Decrypt");complex<double>* dvec = scheme.decrypt(secretKey, cipher);timeutils.stop("Decrypt");StringUtils::compare(mvec, dvec, n, "val");cout << "!!! END TEST ENCRYPT By SK !!!" << endl;
}void TestScheme::testDecryptForShare(long logq, long logp, long logn, long logErrorBound) {cout << "!!! START TEST Decrypt for Share !!!" << endl;double sigma1 = 3.2 * sqrt(2);cout << "Note : encryption std is changed to sigma1 = " << sigma1 << endl;srand(time(NULL));SetNumThreads(8);TimeUtils timeutils;Ring ring;SecretKey secretKey(ring);Scheme scheme(secretKey, ring);long n = (1 << logn);complex<double>* mvec = EvaluatorUtils::randomComplexArray(n);Ciphertext cipher;timeutils.start("Encrypt by sk");scheme.encryptBySk(cipher, secretKey, mvec, n, logp, logq, sigma1);timeutils.stop("Encrypt by sk");timeutils.start("Decrypt by share");complex<double>* dvecShare = scheme.decryptForShare(secretKey, cipher, logErrorBound);complex<double>* dvec = scheme.decrypt(secretKey, cipher);timeutils.stop("Decrypt by share");for (long i = 0; i < n; ++i) {cout << "---------------------" << endl;cout << "plain : " << i << " :" << mvec[i] << endl;cout << "decrypt : " << i << " :" << dvec[i] << endl;cout << "decryptForShare : " << i << " :" << dvecShare[i] << endl;cout << "dec error : " << i << " :" << (mvec[i]-dvec[i]) << endl;cout << "dec and decForShare error : " << i << " :" << (dvec[i]-dvecShare[i]) << endl;cout << "---------------------" << endl;}cout << "!!! END TEST Decrypt for Share !!!" << endl;
}void TestScheme::testEncryptSingle(long logq, long logp) {cout << "!!! START TEST ENCRYPT SINGLE !!!" << endl;srand(time(NULL));SetNumThreads(8);TimeUtils timeutils;Ring ring;SecretKey secretKey(ring);Scheme scheme(secretKey, ring);complex<double> mval = EvaluatorUtils::randomComplex();Ciphertext cipher;timeutils.start("Encrypt Single");scheme.encryptSingle(cipher, mval, logp, logq);timeutils.stop("Encrypt Single");complex<double> dval = scheme.decryptSingle(secretKey, cipher);StringUtils::compare(mval, dval, "val");cout << "!!! END TEST ENCRYPT SINGLE !!!" << endl;
}void TestScheme::testAdd(long logq, long logp, long logn) {cout << "!!! START TEST ADD !!!" << endl;srand(time(NULL));SetNumThreads(8);TimeUtils timeutils;Ring ring;SecretKey secretKey(ring);Scheme scheme(secretKey, ring);long n = (1 << logn);complex<double>* mvec1 = EvaluatorUtils::randomComplexArray(n);complex<double>* mvec2 = EvaluatorUtils::randomComplexArray(n);complex<double>* madd = new complex<double>[n];for(long i = 0; i < n; i++) {madd[i] = mvec1[i] + mvec2[i];}Ciphertext cipher1, cipher2;scheme.encrypt(cipher1, mvec1, n, logp, logq);scheme.encrypt(cipher2, mvec2, n, logp, logq);timeutils.start("Addition");scheme.addAndEqual(cipher1, cipher2);timeutils.stop("Addition");complex<double>* dadd = scheme.decrypt(secretKey, cipher1);StringUtils::compare(madd, dadd, n, "add");cout << "!!! END TEST ADD !!!" << endl;
}void TestScheme::testMult(long logq, long logp, long logn) {cout << "!!! START TEST MULT !!!" << endl;srand(time(NULL));SetNumThreads(8);TimeUtils timeutils;Ring ring;SecretKey secretKey(ring);Scheme scheme(secretKey, ring);long n = (1 << logn);complex<double>* mvec1 = EvaluatorUtils::randomComplexArray(n);complex<double>* mvec2 = EvaluatorUtils::randomComplexArray(n);complex<double>* mmult = new complex<double>[n];for(long i = 0; i < n; i++) {mmult[i] = mvec1[i] * mvec2[i];}Ciphertext cipher1, cipher2;scheme.encrypt(cipher1, mvec1, n, logp, logq);scheme.encrypt(cipher2, mvec2, n, logp, logq);timeutils.start("Multiplication");scheme.multAndEqual(cipher1, cipher2);timeutils.stop("Multiplication");complex<double>* dmult = scheme.decrypt(secretKey, cipher1);StringUtils::compare(mmult, dmult, n, "mult");cout << "!!! END TEST MULT !!!" << endl;
}void TestScheme::testiMult(long logq, long logp, long logn) {cout << "!!! START TEST i MULTIPLICATION !!!" << endl;srand(time(NULL));SetNumThreads(8);TimeUtils timeutils;Ring ring;SecretKey secretKey(ring);Scheme scheme(secretKey, ring);long n = (1 << logn);complex<double>* mvec = EvaluatorUtils::randomComplexArray(n);complex<double>* imvec = new complex<double>[n];for (long i = 0; i < n; ++i) {imvec[i].real(-mvec[i].imag());imvec[i].imag(mvec[i].real());}Ciphertext cipher;scheme.encrypt(cipher, mvec, n, logp, logq);timeutils.start("Multiplication by i");scheme.imultAndEqual(cipher);timeutils.stop("Multiplication by i");complex<double>* idvec = scheme.decrypt(secretKey, cipher);StringUtils::compare(imvec, idvec, n, "imult");cout << "!!! END TEST i MULTIPLICATION !!!" << endl;
}//----------------------------------------------------------------------------------
//   ROTATE & CONJUGATE
//----------------------------------------------------------------------------------void TestScheme::testRotateFast(long logq, long logp, long logn, long logr) {cout << "!!! START TEST ROTATE FAST !!!" << endl;srand(time(NULL));SetNumThreads(8);TimeUtils timeutils;Ring ring;SecretKey secretKey(ring);Scheme scheme(secretKey, ring);long n = (1 << logn);long r = (1 << logr);scheme.addLeftRotKey(secretKey, r);complex<double>* mvec = EvaluatorUtils::randomComplexArray(n);Ciphertext cipher;scheme.encrypt(cipher, mvec, n, logp, logq);timeutils.start("Left Rotate Fast");scheme.leftRotateFastAndEqual(cipher, r);timeutils.stop("Left Rotate Fast");complex<double>* dvec = scheme.decrypt(secretKey, cipher);EvaluatorUtils::leftRotateAndEqual(mvec, n, r);StringUtils::compare(mvec, dvec, n, "rot");cout << "!!! END TEST ROTATE BY POWER OF 2 BATCH !!!" << endl;
}void TestScheme::testConjugate(long logq, long logp, long logn) {cout << "!!! START TEST CONJUGATE !!!" << endl;srand(time(NULL));SetNumThreads(8);TimeUtils timeutils;Ring ring;SecretKey secretKey(ring);Scheme scheme(secretKey, ring);scheme.addConjKey(secretKey);long n = (1 << logn);complex<double>* mvec = EvaluatorUtils::randomComplexArray(n);complex<double>* mvecconj = new complex<double>[n];for (long i = 0; i < n; ++i) {mvecconj[i] = conj(mvec[i]);}Ciphertext cipher;scheme.encrypt(cipher, mvec, n, logp, logq);timeutils.start("Conjugate");scheme.conjugateAndEqual(cipher);timeutils.stop("Conjugate");complex<double>* dvecconj = scheme.decrypt(secretKey, cipher);StringUtils::compare(mvecconj, dvecconj, n, "conj");cout << "!!! END TEST CONJUGATE !!!" << endl;
}//----------------------------------------------------------------------------------
//   POWER & PRODUCT TESTS
//----------------------------------------------------------------------------------void TestScheme::testPowerOf2(long logq, long logp, long logn, long logdeg) {cout << "!!! START TEST POWER OF 2 !!!" << endl;srand(time(NULL));SetNumThreads(8);TimeUtils timeutils;Ring ring;SecretKey secretKey(ring);Scheme scheme(secretKey, ring);SchemeAlgo algo(scheme);long n = 1 << logn;long degree = 1 << logdeg;complex<double>* mvec = new complex<double>[n];complex<double>* mpow = new complex<double>[n];for (long i = 0; i < n; ++i) {mvec[i] = EvaluatorUtils::randomCircle();mpow[i] = pow(mvec[i], degree);}Ciphertext cipher, cpow;scheme.encrypt(cipher, mvec, n, logp, logq);timeutils.start("Power of 2");algo.powerOf2(cpow, cipher, logp, logdeg);timeutils.stop("Power of 2");complex<double>* dpow = scheme.decrypt(secretKey, cpow);StringUtils::compare(mpow, dpow, n, "pow2");cout << "!!! END TEST POWER OF 2 !!!" << endl;
}//-----------------------------------------void TestScheme::testPower(long logq, long logp, long logn, long degree) {cout << "!!! START TEST POWER !!!" << endl;srand(time(NULL));SetNumThreads(8);TimeUtils timeutils;Ring ring;SecretKey secretKey(ring);Scheme scheme(secretKey, ring);SchemeAlgo algo(scheme);long n = 1 << logn;complex<double>* mvec = EvaluatorUtils::randomCircleArray(n);complex<double>* mpow = new complex<double>[n];for (long i = 0; i < n; ++i) {mpow[i] = pow(mvec[i], degree);}Ciphertext cipher, cpow;scheme.encrypt(cipher, mvec, n, logp, logq);timeutils.start("Power");algo.power(cpow, cipher, logp, degree);timeutils.stop("Power");complex<double>* dpow = scheme.decrypt(secretKey, cpow);StringUtils::compare(mpow, dpow, n, "pow");cout << "!!! END TEST POWER !!!" << endl;
}//----------------------------------------------------------------------------------
//   FUNCTION TESTS
//----------------------------------------------------------------------------------void TestScheme::testInverse(long logq, long logp, long logn, long steps) {cout << "!!! START TEST INVERSE !!!" << endl;srand(time(NULL));SetNumThreads(8);TimeUtils timeutils;Ring ring;SecretKey secretKey(ring);Scheme scheme(secretKey, ring);SchemeAlgo algo(scheme);long n = 1 << logn;complex<double>* mvec = EvaluatorUtils::randomCircleArray(n, 0.1);complex<double>* minv = new complex<double>[n];for (long i = 0; i < n; ++i) {minv[i] = 1. / mvec[i];}Ciphertext cipher, cinv;scheme.encrypt(cipher, mvec, n, logp, logq);timeutils.start("Inverse");algo.inverse(cinv, cipher, logp, steps);timeutils.stop("Inverse");complex<double>* dinv = scheme.decrypt(secretKey, cinv);StringUtils::compare(minv, dinv, n, "inv");cout << "!!! END TEST INVERSE !!!" << endl;
}void TestScheme::testLogarithm(long logq, long logp, long logn, long degree) {cout << "!!! START TEST LOGARITHM !!!" << endl;srand(time(NULL));SetNumThreads(8);TimeUtils timeutils;Ring ring;SecretKey secretKey(ring);Scheme scheme(secretKey, ring);SchemeAlgo algo(scheme);long n = 1 << logn;complex<double>* mvec = EvaluatorUtils::randomComplexArray(n, 0.1);complex<double>* mlog = new complex<double>[n];for (long i = 0; i < n; ++i) {mlog[i] = log(mvec[i] + 1.);}Ciphertext cipher, clog;scheme.encrypt(cipher, mvec, n, logp, logq);timeutils.start(LOGARITHM);algo.function(clog, cipher, LOGARITHM, logp, degree);timeutils.stop(LOGARITHM);complex<double>* dlog = scheme.decrypt(secretKey, clog);StringUtils::compare(mlog, dlog, n, LOGARITHM);cout << "!!! END TEST LOGARITHM !!!" << endl;
}void TestScheme::testExponent(long logq, long logp, long logn, long degree) {cout << "!!! START TEST EXPONENT !!!" << endl;srand(time(NULL));SetNumThreads(8);TimeUtils timeutils;Ring ring;SecretKey secretKey(ring);Scheme scheme(secretKey, ring);SchemeAlgo algo(scheme);long n = 1 << logn;complex<double>* mvec = EvaluatorUtils::randomComplexArray(n);complex<double>* mexp = new complex<double>[n];for (long i = 0; i < n; ++i) {mexp[i] = exp(mvec[i]);}Ciphertext cipher, cexp;scheme.encrypt(cipher, mvec, n, logp, logq);timeutils.start(EXPONENT);algo.function(cexp, cipher, EXPONENT, logp, degree);timeutils.stop(EXPONENT);complex<double>* dexp = scheme.decrypt(secretKey, cexp);StringUtils::compare(mexp, dexp, n, EXPONENT);cout << "!!! END TEST EXPONENT !!!" << endl;
}void TestScheme::testExponentLazy(long logq, long logp, long logn, long degree) {cout << "!!! START TEST EXPONENT LAZY !!!" << endl;srand(time(NULL));SetNumThreads(8);TimeUtils timeutils;Ring ring;SecretKey secretKey(ring);Scheme scheme(secretKey, ring);SchemeAlgo algo(scheme);long n = 1 << logn;complex<double>* mvec = EvaluatorUtils::randomComplexArray(n);complex<double>* mexp = new complex<double>[n];for (long i = 0; i < n; ++i) {mexp[i] = exp(mvec[i]);}Ciphertext cipher, cexp;scheme.encrypt(cipher, mvec, n, logp, logQ);timeutils.start(EXPONENT + " lazy");algo.functionLazy(cexp, cipher, EXPONENT, logp, degree);timeutils.stop(EXPONENT + " lazy");complex<double>* dexp = scheme.decrypt(secretKey, cexp);StringUtils::compare(mexp, dexp, n, EXPONENT);cout << "!!! END TEST EXPONENT LAZY !!!" << endl;
}//-----------------------------------------void TestScheme::testSigmoid(long logq, long logp, long logn, long degree) {cout << "!!! START TEST SIGMOID !!!" << endl;srand(time(NULL));SetNumThreads(8);TimeUtils timeutils;Ring ring;SecretKey secretKey(ring);Scheme scheme(secretKey, ring);SchemeAlgo algo(scheme);long n = 1 << logn;complex<double>* mvec = EvaluatorUtils::randomComplexArray(n);complex<double>* msig = new complex<double>[n];for (long i = 0; i < n; ++i) {msig[i] = exp(mvec[i]) / (1. + exp(mvec[i]));}Ciphertext cipher, csig;scheme.encrypt(cipher, mvec, n, logp, logq);timeutils.start(SIGMOID);algo.function(csig, cipher, SIGMOID, logp, degree);timeutils.stop(SIGMOID);complex<double>* dsig = scheme.decrypt(secretKey, csig);StringUtils::compare(msig, dsig, n, SIGMOID);cout << "!!! END TEST SIGMOID !!!" << endl;
}void TestScheme::testSigmoidLazy(long logq, long logp, long logn, long degree) {cout << "!!! START TEST SIGMOID LAZY !!!" << endl;srand(time(NULL));
//  SetNumThreads(8);TimeUtils timeutils;Ring ring;SecretKey secretKey(ring);Scheme scheme(secretKey, ring);SchemeAlgo algo(scheme);long n = 1 << logn;complex<double>* mvec = EvaluatorUtils::randomComplexArray(n);complex<double>* msig = new complex<double>[n];for (long i = 0; i < n; ++i) {msig[i] = exp(mvec[i]) / (1. + exp(mvec[i]));}Ciphertext cipher, csig;scheme.encrypt(cipher, mvec, n, logp, logq);timeutils.start(SIGMOID + " lazy");algo.functionLazy(csig, cipher, SIGMOID, logp, degree);timeutils.stop(SIGMOID + " lazy");complex<double>* dsig = scheme.decrypt(secretKey, csig);StringUtils::compare(msig, dsig, n, SIGMOID);cout << "!!! END TEST SIGMOID LAZY !!!" << endl;
}void TestScheme::testWriteAndRead(long logq, long logp, long logSlots) {cout << "!!! START TEST WRITE AND READ !!!" << endl;cout << "!!! END TEST WRITE AND READ !!!" << endl;
}void TestScheme::testBootstrap(long logq, long logp, long logSlots, long logT) {cout << "!!! START TEST BOOTSTRAP !!!" << endl;srand(time(NULL));SetNumThreads(8);TimeUtils timeutils;Ring ring;SecretKey secretKey(ring);Scheme scheme(secretKey, ring);timeutils.start("Key generating");scheme.addBootKey(secretKey, logSlots, logq + 4);timeutils.stop("Key generated");long slots = (1 << logSlots);complex<double>* mvec = EvaluatorUtils::randomComplexArray(slots);Ciphertext cipher;scheme.encrypt(cipher, mvec, slots, logp, logq);cout << "cipher logq before: " << cipher.logq << endl;scheme.modDownToAndEqual(cipher, logq);scheme.normalizeAndEqual(cipher);cipher.logq = logQ;cipher.logp = logq + 4;Ciphertext rot;timeutils.start("SubSum");for (long i = logSlots; i < logNh; ++i) {scheme.leftRotateFast(rot, cipher, (1 << i));scheme.addAndEqual(cipher, rot);}scheme.divByPo2AndEqual(cipher, logNh);timeutils.stop("SubSum");timeutils.start("CoeffToSlot");scheme.coeffToSlotAndEqual(cipher);timeutils.stop("CoeffToSlot");timeutils.start("EvalExp");scheme.evalExpAndEqual(cipher, logT);timeutils.stop("EvalExp");timeutils.start("SlotToCoeff");scheme.slotToCoeffAndEqual(cipher);timeutils.stop("SlotToCoeff");cipher.logp = logp;cout << "cipher logq after: " << cipher.logq << endl;complex<double>* dvec = scheme.decrypt(secretKey, cipher);StringUtils::compare(mvec, dvec, slots, "boot");cout << "!!! END TEST BOOTSRTAP !!!" << endl;
}void TestScheme::testBootstrapSingleReal(long logq, long logp, long logT) {cout << "!!! START TEST BOOTSTRAP SINGLE REAL !!!" << endl;srand(time(NULL));SetNumThreads(8);TimeUtils timeutils;Ring ring;SecretKey secretKey(ring);Scheme scheme(secretKey, ring);timeutils.start("Key generating");scheme.addBootKey(secretKey, 0, logq + 4);timeutils.stop("Key generated");double mval = EvaluatorUtils::randomReal();Ciphertext cipher;scheme.encryptSingle(cipher, mval, logp, logq);cout << "cipher logq before: " << cipher.logq << endl;scheme.modDownToAndEqual(cipher, logq);scheme.normalizeAndEqual(cipher);cipher.logq = logQ;Ciphertext rot, cconj;timeutils.start("SubSum");for (long i = 0; i < logNh; ++i) {scheme.leftRotateFast(rot, cipher, 1 << i);scheme.addAndEqual(cipher, rot);}scheme.conjugate(cconj, cipher);scheme.addAndEqual(cipher, cconj);scheme.divByPo2AndEqual(cipher, logN);timeutils.stop("SubSum");timeutils.start("EvalExp");scheme.evalExpAndEqual(cipher, logT);timeutils.stop("EvalExp");cout << "cipher logq after: " << cipher.logq << endl;cipher.logp = logp;complex<double> dval = scheme.decryptSingle(secretKey, cipher);StringUtils::compare(mval, dval.real(), "boot");cout << "!!! END TEST BOOTSRTAP SINGLE REAL !!!" << endl;
}}  // namespace heaan

StringUtils.h

#ifndef HEAAN_STRINGUTILS_H_
#define HEAAN_STRINGUTILS_H_#include <NTL/ZZ.h>#include <complex>
#include <string>namespace heaan {class StringUtils {public://----------------------------------------------------------------------------------//   SHOW ARRAY//----------------------------------------------------------------------------------static void showVec(long* vals, long size);static void showVec(double* vals, long size);static void showVec(std::complex<double>* vals, long size);static void showVec(NTL::ZZ* vals, long size);//----------------------------------------------------------------------------------//   SHOW & COMPARE ARRAY//----------------------------------------------------------------------------------static void compare(double val1, double val2, std::string prefix);static void compare(std::complex<double> val1, std::complex<double> val2, std::string prefix);static void compare(double* vals1, double* vals2, long size, std::string prefix);static void compare(std::complex<double>* vals1, std::complex<double>* vals2, long size, std::string prefix);static void compare(double* vals1, double val2, long size, std::string prefix);static void compare(std::complex<double>* vals1, std::complex<double> val2, long size, std::string prefix);static void compare(double val1, double* vals2, long size, std::string prefix);static void compare(std::complex<double> val1, std::complex<double>* vals2, long size, std::string prefix);};}  // namespace heaan#endif

StringUtils.cpp

#include "StringUtils.h"using namespace std;namespace heaan {//----------------------------------------------------------------------------------
//   SHOW ARRAY
//----------------------------------------------------------------------------------void StringUtils::showVec(long* vals, long size) {cout << "[";cout << vals[0];for (long i = 1; i < size; ++i) {cout << ", " << vals[i];}cout << "]" << endl;
}void StringUtils::showVec(double* vals, long size) {cout << "[";cout << vals[0];for (long i = 1; i < size; ++i) {cout << ", " << vals[i];}cout << "]" << endl;
}void StringUtils::showVec(complex<double>* vals, long size) {cout << "[";cout << vals[0];for (long i = 1; i < size; ++i) {cout << ", " << vals[i];}cout << "]" << endl;
}void StringUtils::showVec(NTL::ZZ* vals, long size) {cout << "[";cout << vals[0];for (long i = 1; i < size; ++i) {cout << ", " << vals[i];}cout << "]" << endl;
}//----------------------------------------------------------------------------------
//   SHOW & COMPARE ARRAY
//----------------------------------------------------------------------------------void StringUtils::compare(double val1, double val2, string prefix) {cout << "---------------------" << endl;cout << "m" + prefix + ":" << val1 << endl;cout << "d" + prefix + ":" << val2 << endl;cout << "e" + prefix + ":" << val1-val2 << endl;cout << "---------------------" << endl;
}void StringUtils::compare(complex<double> val1, complex<double> val2, string prefix) {cout << "---------------------" << endl;cout << "m" + prefix + ":" << val1 << endl;cout << "d" + prefix + ":" << val2 << endl;cout << "e" + prefix + ":" << val1-val2 << endl;cout << "---------------------" << endl;
}void StringUtils::compare(double* vals1, double* vals2, long size, string prefix) {for (long i = 0; i < size; ++i) {cout << "---------------------" << endl;cout << "m" + prefix + ": " << i << " :" << vals1[i] << endl;cout << "d" + prefix + ": " << i << " :" << vals2[i] << endl;cout << "e" + prefix + ": " << i << " :" << (vals1[i]-vals2[i]) << endl;cout << "---------------------" << endl;}
}void StringUtils::compare(complex<double>* vals1, complex<double>* vals2, long size, string prefix) {for (long i = 0; i < size; ++i) {cout << "---------------------" << endl;cout << "m" + prefix + ": " << i << " :" << vals1[i] << endl;cout << "d" + prefix + ": " << i << " :" << vals2[i] << endl;cout << "e" + prefix + ": " << i << " :" << (vals1[i]-vals2[i]) << endl;cout << "---------------------" << endl;}
}void StringUtils::compare(double* vals1, double val2, long size, string prefix) {for (long i = 0; i < size; ++i) {cout << "---------------------" << endl;cout << "m" + prefix + ": " << i << " :" << vals1[i] << endl;cout << "d" + prefix + ": " << i << " :" << val2 << endl;cout << "e" + prefix + ": " << i << " :" << vals1[i]-val2 << endl;cout << "---------------------" << endl;}
}void StringUtils::compare(complex<double>* vals1, complex<double> val2, long size, string prefix) {for (long i = 0; i < size; ++i) {cout << "---------------------" << endl;cout << "m" + prefix + ": " << i << " :" << vals1[i] << endl;cout << "d" + prefix + ": " << i << " :" << val2 << endl;cout << "e" + prefix + ": " << i << " :" << vals1[i]-val2 << endl;cout << "---------------------" << endl;}
}void StringUtils::compare(double val1, double* vals2, long size, string prefix) {for (long i = 0; i < size; ++i) {cout << "---------------------" << endl;cout << "m" + prefix + ": " << i << " :" << val1 << endl;cout << "d" + prefix + ": " << i << " :" << vals2[i] << endl;cout << "e" + prefix + ": " << i << " :" << val1-vals2[i] << endl;cout << "---------------------" << endl;}
}void StringUtils::compare(complex<double> val1, complex<double>* vals2, long size, string prefix) {for (long i = 0; i < size; ++i) {cout << "---------------------" << endl;cout << "m" + prefix + ": " << i << " :" << val1 << endl;cout << "d" + prefix + ": " << i << " :" << vals2[i] << endl;cout << "e" + prefix + ": " << i << " :" << val1-vals2[i] << endl;cout << "---------------------" << endl;}
}}  // namespace heaan

SerializationUtils.h

#ifndef HEAAN_SERIALIZATIONUTILS_H_
#define HEAAN_SERIALIZATIONUTILS_H_#include <iostream>
#include <string>#include "Ciphertext.h"
#include "Params.h"
#include "Key.h"namespace heaan {class SerializationUtils {public:static void writeCiphertext(Ciphertext& ciphertext, std::string path);static Ciphertext* readCiphertext(std::string path);static void writeKey(Key* key, std::string path);static Key* readKey(std::string path);
};}  // namespace heaan#endif /* SERIALIZATIONUTILS_H_ */

SerializationUtils.cpp

#include "SerializationUtils.h"using namespace std;
using namespace NTL;namespace heaan {void SerializationUtils::writeCiphertext(Ciphertext& cipher, string path) {fstream fout;fout.open(path, ios::binary|ios::out);long n = cipher.n;long logp = cipher.logp;long logq = cipher.logq;fout.write(reinterpret_cast<char*>(&n), sizeof(long));fout.write(reinterpret_cast<char*>(&logp), sizeof(long));fout.write(reinterpret_cast<char*>(&logq), sizeof(long));long np = ceil(((double)logq + 1)/8);ZZ q = conv<ZZ>(1) << logq;unsigned char* bytes = new unsigned char[np];for (long i = 0; i < N; ++i) {cipher.ax[i] %= q;BytesFromZZ(bytes, cipher.ax[i], np);fout.write(reinterpret_cast<char*>(bytes), np);}for (long i = 0; i < N; ++i) {cipher.bx[i] %= q;BytesFromZZ(bytes, cipher.bx[i], np);fout.write(reinterpret_cast<char*>(bytes), np);}fout.close();
}Ciphertext* SerializationUtils::readCiphertext(string path) {long n, logp, logq;fstream fin;fin.open(path, ios::binary|ios::in);fin.read(reinterpret_cast<char*>(&n), sizeof(long));fin.read(reinterpret_cast<char*>(&logp), sizeof(long));fin.read(reinterpret_cast<char*>(&logq), sizeof(long));long np = ceil(((double)logq + 1)/8);unsigned char* bytes = new unsigned char[np];Ciphertext cipher(logp, logq, n);for (long i = 0; i < N; ++i) {fin.read(reinterpret_cast<char*>(bytes), np);ZZFromBytes(cipher.ax[i], bytes, np);}for (long i = 0; i < N; ++i) {fin.read(reinterpret_cast<char*>(bytes), np);ZZFromBytes(cipher.bx[i], bytes, np);}fin.close();return &cipher;
}void SerializationUtils::writeKey(Key* key, string path) {fstream fout;fout.open(path, ios::binary|ios::out);fout.write(reinterpret_cast<char*>(key->rax), Nnprimes*sizeof(uint64_t));fout.write(reinterpret_cast<char*>(key->rbx), Nnprimes*sizeof(uint64_t));fout.close();
}Key* SerializationUtils::readKey(string path) {Key key;fstream fin;fin.open(path, ios::binary|ios::in);fin.read(reinterpret_cast<char*>(key.rax), Nnprimes*sizeof(uint64_t));fin.read(reinterpret_cast<char*>(key.rbx), Nnprimes*sizeof(uint64_t));fin.close();return &key;
}}  // namespace heaan

SecretKey.h

一个向量存储系数向量

#ifndef HEAAN_SECRETKEY_H_
#define HEAAN_SECRETKEY_H_#include <NTL/ZZ.h>#include "Ring.h"namespace heaan {class SecretKey {public:NTL::ZZ* sx = new NTL::ZZ[N];SecretKey(Ring& ring);};}  // namespace heaan#endif

SecretKey.cpp

根据HWT(h)分布采样

#include "SecretKey.h"namespace heaan {SecretKey::SecretKey(Ring& ring) {ring.sampleHWT(sx);
}}  // namespace heaan

Plaintext.h

参数:logp, logq, n (都是啥?)

#ifndef HEAAN_PLAINTEXT_H_
#define HEAAN_PLAINTEXT_H_#include <NTL/ZZ.h>
#include "Params.h"namespace heaan {class Plaintext {public:NTL::ZZ* mx = new NTL::ZZ[N];long logp;long logq;long n;Plaintext(long logp = 0, long logq = 0, long n = 0);virtual ~Plaintext();
};}  // namespace heaan#endif

Plaintext.cpp

#include "Plaintext.h"namespace heaan {Plaintext::Plaintext(long logp, long logq, long n) : logp(logp), logq(logq), n(n) {}Plaintext::~Plaintext() {delete[] mx;
}}  // namespace heaan

Params.h

定义了一堆参数

#ifndef HEAAN_PARAMS_H_
#define HEAAN_PARAMS_H_#include <NTL/ZZ.h>namespace heaan {static const long logN = 16;
static const long logQ = 800; // 128-bit securitystatic const double sigma = 3.2;
static const long h = 64;
static const long pbnd = 59.0;
static const long kbar = pbnd + 1;
static const long kbar2 = 2 * kbar;
static const long logNh = (logN - 1);
static const long logQQ = (2 * logQ);
static const long N = (1 << logN);
static const long Nh = (1 << logNh);
static const long M = (N << 1);
static const long nprimes = (2 + logN + 4 * logQ + pbnd - 1) / pbnd;
static const long Nnprimes = (nprimes << logN);
static const long cbnd = (logQQ + NTL_ZZ_NBITS - 1) / NTL_ZZ_NBITS;
static const long bignum = 0xfffffff;
static const NTL::ZZ Q = NTL::power2_ZZ(logQ);
static const NTL::ZZ QQ = NTL::power2_ZZ(logQQ);}  // namespace heaan#endif /* PARAMS_H_ */

Ciphertext.h

#ifndef HEAAN_CIPHERTEXT_H_
#define HEAAN_CIPHERTEXT_H_#include <NTL/ZZ.h>#include <fstream>
#include "Params.h"namespace heaan {class Ciphertext {public:NTL::ZZ* ax = new NTL::ZZ[N];NTL::ZZ* bx = new NTL::ZZ[N];long logp;long logq;long n;Ciphertext(long logp = 0, long logq = 0, long n = 0);Ciphertext(const Ciphertext& o);void copyParams(Ciphertext& o);void copy(Ciphertext& o);void free();virtual ~Ciphertext();};}  // namespace heaan#endif

Ciphertext.cpp

#include "Ciphertext.h"#include <NTL/tools.h>using namespace std;
using namespace NTL;namespace heaan {Ciphertext::Ciphertext(long logp, long logq, long n) : logp(logp), logq(logq), n(n) {}Ciphertext::Ciphertext(const Ciphertext& o) : logp(o.logp), logq(o.logq), n(o.n) {for (long i = 0; i < N; ++i) {ax[i] = o.ax[i];bx[i] = o.bx[i];}
}void Ciphertext::copyParams(Ciphertext& o) {logp = o.logp;logq = o.logq;n = o.n;
}void Ciphertext::copy(Ciphertext& o) {copyParams(o);for (long i = 0; i < N; ++i) {ax[i] = o.ax[i];bx[i] = o.bx[i];}
}void Ciphertext::free() {for (long i = 0; i < N; ++i) {clear(ax[i]);clear(bx[i]);}
}Ciphertext::~Ciphertext() {delete[] ax;delete[] bx;
}}  // namespace heaan

Key.h

#ifndef HEAAN_KEY_H_
#define HEAAN_KEY_H_#include <NTL/ZZ.h>
#include "Params.h"namespace heaan {class Key {public:uint64_t* rax = new uint64_t[Nnprimes]();uint64_t* rbx = new uint64_t[Nnprimes]();Key();virtual ~Key();
};}  // namespace heaan#endif

Key.cpp

#include "Key.h"namespace heaan {Key::Key() {}Key::~Key() {delete[] rax;delete[] rbx;
}}  // namespace heaan

BootContext.h

#ifndef HEAAN_BOOTCONTEXT_H_
#define HEAAN_BOOTCONTEXT_H_#include <NTL/ZZ.h>namespace heaan {class BootContext {public:uint64_t** rpvec;uint64_t** rpvecInv;uint64_t* rp1;uint64_t* rp2;long* bndvec;long* bndvecInv;long bnd1;long bnd2;long logp;BootContext(uint64_t** rpvec = NULL, uint64_t** rpvecInv = NULL, uint64_t* rp1 = NULL, uint64_t* rp2 = NULL,long* bndvec = NULL, long* bndvecInv = NULL, long bnd1 = 0, long bnd2 = 0, long logp = 0);};}  // namespace heaan#endif

BootContext.cpp

#include "BootContext.h"namespace heaan {BootContext::BootContext(uint64_t** rpvec, uint64_t** rpvecInv, uint64_t* rp1, uint64_t* rp2,long* bndvec, long* bndvecInv, long bnd1, long bnd2, long logp) :rpvec(rpvec), rpvecInv(rpvecInv), rp1(rp1), rp2(rp2),bndvec(bndvec), bndvecInv(bndvecInv), bnd1(bnd1), bnd2(bnd2), logp(logp){}}  // namespace heaan

EvaluatorUtils.h

#ifndef HEAAN_EVALUATORUTILS_H_
#define HEAAN_EVALUATORUTILS_H_#include <NTL/RR.h>
#include <NTL/ZZ.h>
#include <complex>namespace heaan {class EvaluatorUtils {public://----------------------------------------------------------------------------------//   RANDOM REAL AND COMPLEX NUMBERS//----------------------------------------------------------------------------------static double randomReal(double bound = 1.0);static std::complex<double> randomComplex(double bound = 1.0);static std::complex<double> randomCircle(double anglebound = 1.0);static double* randomRealArray(long size, double bound = 1.0);static std::complex<double>* randomComplexArray(long size, double bound = 1.0);static std::complex<double>* randomCircleArray(long size, double bound = 1.0);//----------------------------------------------------------------------------------//   DOUBLE & RR <-> ZZ//----------------------------------------------------------------------------------static double scaleDownToReal(const NTL::ZZ& x, const long logp);static NTL::ZZ scaleUpToZZ(const double x, const long logp);static NTL::ZZ scaleUpToZZ(const NTL::RR& x, const long logp);//----------------------------------------------------------------------------------//   ROTATIONS//----------------------------------------------------------------------------------static void leftRotateAndEqual(std::complex<double>* vals, const long n, const long r);static void rightRotateAndEqual(std::complex<double>* vals, const long n, const long r);};}  // namespace heaan#endif

EvaluatorUtils.cpp

#include "EvaluatorUtils.h"#include <cmath>
#include <complex>
#include <cstdlib>using namespace std;
using namespace NTL;namespace heaan {//----------------------------------------------------------------------------------
//   RANDOM REAL AND COMPLEX NUMBERS
//----------------------------------------------------------------------------------double EvaluatorUtils::randomReal(double bound)  {return (double) rand()/(RAND_MAX) * bound;
}complex<double> EvaluatorUtils::randomComplex(double bound) {complex<double> res;res.real(randomReal(bound));res.imag(randomReal(bound));return res;
}complex<double> EvaluatorUtils::randomCircle(double anglebound) {double angle = randomReal(anglebound);complex<double> res;res.real(cos(angle * 2 * M_PI));res.imag(sin(angle * 2 * M_PI));return res;
}double* EvaluatorUtils::randomRealArray(long n, double bound) {double* res = new double[n];for (long i = 0; i < n; ++i) {res[i] = randomReal(bound);}return res;
}complex<double>* EvaluatorUtils::randomComplexArray(long n, double bound) {complex<double>* res = new complex<double>[n];for (long i = 0; i < n; ++i) {res[i] = randomComplex(bound);}return res;
}complex<double>* EvaluatorUtils::randomCircleArray(long n, double bound) {complex<double>* res = new complex<double>[n];for (long i = 0; i < n; ++i) {res[i] = randomCircle(bound);}return res;
}//----------------------------------------------------------------------------------
//   DOUBLE & RR <-> ZZ
//----------------------------------------------------------------------------------double EvaluatorUtils::scaleDownToReal(const ZZ& x, const long logp) {RR xp = to_RR(x);xp.e -= logp;return to_double(xp);
}ZZ EvaluatorUtils::scaleUpToZZ(const double x, const long logp) {return scaleUpToZZ(to_RR(x), logp);
}ZZ EvaluatorUtils::scaleUpToZZ(const RR& x, const long logp) {RR xp = MakeRR(x.x, x.e + logp);return RoundToZZ(xp);
}//----------------------------------------------------------------------------------
//   ROTATIONS
//----------------------------------------------------------------------------------void EvaluatorUtils::leftRotateAndEqual(complex<double>* vals, const long n, const long r) {long rem = r % n;if(rem != 0) {long divisor = GCD(rem, n);long steps = n / divisor;for (long i = 0; i < divisor; ++i) {complex<double> tmp = vals[i];long idx = i;for (long j = 0; j < steps - 1; ++j) {vals[idx] = vals[(idx + rem) % n];idx = (idx + rem) % n;}vals[idx] = tmp;}}
}void EvaluatorUtils::rightRotateAndEqual(complex<double>* vals, const long n, const long r) {long rem = r % n;rem = (n - rem) % n;leftRotateAndEqual(vals, n, rem);
}}  // namespace heaan

Ring.h

#ifndef HEAAN_RING_H_
#define HEAAN_RING_H_#include <NTL/ZZ.h>
#include <NTL/RR.h>
#include <complex>
#include <map>
#include "BootContext.h"
#include "RingMultiplier.h"namespace heaan {static NTL::RR Pi = NTL::ComputePi_RR();class Ring {public:NTL::ZZ* qpows;long* rotGroup;std::complex<double>* ksiPows;std::map<long, BootContext*> bootContextMap;RingMultiplier multiplier;Ring();//----------------------------------------------------------------------------------//   Encode & Decode//----------------------------------------------------------------------------------void arrayBitReverse(std::complex<double>* vals, long size);void EMB(std::complex<double>* vals, long size);void EMBInvLazy(std::complex<double>* vals, long size);void EMBInv(std::complex<double>* vals, long size);void encode(NTL::ZZ* mx, double* vals, long slots, long logp);void encode(NTL::ZZ* mx, std::complex<double>* vals, long slots, long logp);void decode(NTL::ZZ* mx, std::complex<double>* vals, long slots, long logp, long logq);//----------------------------------------------------------------------------------//   CONTEXT//----------------------------------------------------------------------------------void addBootContext(long logSlots, long logp);//----------------------------------------------------------------------------------//   MULTIPLICATION//----------------------------------------------------------------------------------long maxBits(const NTL::ZZ* f, long n);void CRT(uint64_t* rx, NTL::ZZ* x, const long np);void addNTTAndEqual(uint64_t* ra, uint64_t* rb, const long np);void mult(NTL::ZZ* x, NTL::ZZ* a, NTL::ZZ* b, long np, const NTL::ZZ& q);void multNTT(NTL::ZZ* x, NTL::ZZ* a, uint64_t* rb, long np, const NTL::ZZ& q);void multDNTT(NTL::ZZ* x, uint64_t* a, uint64_t* rb, long np, const NTL::ZZ& q);void multAndEqual(NTL::ZZ* a, NTL::ZZ* b, long np, const NTL::ZZ& q);void multNTTAndEqual(NTL::ZZ* a, uint64_t* rb, long np, const NTL::ZZ& q);void square(NTL::ZZ* x, NTL::ZZ* a, long np, const NTL::ZZ& q);void squareNTT(NTL::ZZ* x, uint64_t* ra, long np, const NTL::ZZ& q);void squareAndEqual(NTL::ZZ* a, long np, const NTL::ZZ& q);//----------------------------------------------------------------------------------//   OTHER//----------------------------------------------------------------------------------void mod(NTL::ZZ* res, NTL::ZZ* p, const NTL::ZZ& QQ);void modAndEqual(NTL::ZZ* p, const NTL::ZZ& QQ);void negate(NTL::ZZ* res, NTL::ZZ* p);void negateAndEqual(NTL::ZZ* p);void add(NTL::ZZ* res, NTL::ZZ* p1, NTL::ZZ* p2, const NTL::ZZ& QQ);void addAndEqual(NTL::ZZ* p1, NTL::ZZ* p2, const NTL::ZZ& QQ);void sub(NTL::ZZ* res, NTL::ZZ* p1, NTL::ZZ* p2, const NTL::ZZ& QQ);void subAndEqual(NTL::ZZ* p1, NTL::ZZ* p2, const NTL::ZZ& QQ);void subAndEqual2(NTL::ZZ* p1, NTL::ZZ* p2, const NTL::ZZ& QQ);void multByMonomial(NTL::ZZ* res, NTL::ZZ* p, long mDeg);void multByMonomialAndEqual(NTL::ZZ* p, long mDeg);void multByConst(NTL::ZZ* res, NTL::ZZ* p, NTL::ZZ& cnst, const NTL::ZZ& QQ);void multByConstAndEqual(NTL::ZZ* p, NTL::ZZ& cnst, const NTL::ZZ& QQ);void leftShift(NTL::ZZ* res, NTL::ZZ* p, const long bits, const NTL::ZZ& QQ);void leftShiftAndEqual(NTL::ZZ* p, const long bits, const NTL::ZZ& QQ);void doubleAndEqual(NTL::ZZ* p, const NTL::ZZ& QQ);void rightShift(NTL::ZZ* res, NTL::ZZ* p, long bits);void rightShiftAndEqual(NTL::ZZ* p, long bits);//----------------------------------------------------------------------------------//   ROTATION & CONJUGATION//----------------------------------------------------------------------------------void leftRotate(NTL::ZZ* res, NTL::ZZ* p, long r);void conjugate(NTL::ZZ* res, NTL::ZZ* p);//----------------------------------------------------------------------------------//   SAMPLING//----------------------------------------------------------------------------------void subFromGaussAndEqual(NTL::ZZ* res, const NTL::ZZ& q);void subFromGaussAndEqual(NTL::ZZ* res, const NTL::ZZ& q, double _sigma);void addGaussAndEqual(NTL::ZZ* res, const NTL::ZZ& q);void addGaussAndEqual(NTL::ZZ* res, const NTL::ZZ& q, double _sigma);void sampleHWT(NTL::ZZ* res);void sampleZO(NTL::ZZ* res);void sampleUniform2(NTL::ZZ* res, long bits);//----------------------------------------------------------------------------------//   DFT//----------------------------------------------------------------------------------void DFT(std::complex<double>* vals, long n);void IDFTLazy(std::complex<double>* vals, long n);void IDFT(std::complex<double>* vals, long n);};}  // namespace heaan#endif

Ring.cpp

#include "Ring.h"#include <NTL/BasicThreadPool.h>
#include <NTL/lip.h>
#include <NTL/sp_arith.h>
#include <NTL/tools.h>
#include <NTL/vector.h>
#include <NTL/ZZVec.h>
#include <NTL/lip.h>#include "EvaluatorUtils.h"
#include "BootContext.h"using namespace std;
using namespace NTL;namespace heaan {Ring::Ring() {qpows = new ZZ[logQQ + 1];qpows[0] = ZZ(1);for (long i = 1; i < logQQ + 1; ++i) {qpows[i] = qpows[i - 1] << 1;}rotGroup = new long[Nh];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];}void Ring::arrayBitReverse(complex<double>* vals, long n) {for (long i = 1, j = 0; i < n; ++i) {long bit = n >> 1;for (; j >= bit; bit >>= 1) {j -= bit;}j += bit;if (i < j) {swap(vals[i], vals[j]);}}
}void Ring::EMB(complex<double>* vals, long n) {arrayBitReverse(vals, n);for (long len = 2; len <= n; len <<= 1) {for (long i = 0; i < n; i += len) {long lenh = len >> 1;long lenq = len << 2;long gap = M / lenq;for (long j = 0; j < lenh; ++j) {long idx = ((rotGroup[j] % lenq)) * gap;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 Ring::EMBInvLazy(complex<double>* vals, long n) {for (long len = n; len >= 1; len >>= 1) {for (long i = 0; i < n; i += len) {long lenh = len >> 1;long lenq = len << 2;long gap = M / lenq;for (long j = 0; j < lenh; ++j) {long idx = (lenq - (rotGroup[j] % lenq)) * gap;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;}}}arrayBitReverse(vals, n);
}void Ring::EMBInv(complex<double>* vals, long n) {EMBInvLazy(vals, n);for (long i = 0; i < n; ++i) {vals[i] /= n;}
}void Ring::encode(ZZ* mx, double* vals, long slots, long logp) {complex<double>* uvals = new complex<double>[slots];long i, jdx, idx;for (i = 0; i < slots; ++i) {uvals[i].real(vals[i]);}long gap = Nh / slots;EMBInv(uvals, slots);for (i = 0, jdx = Nh, idx = 0; i < slots; ++i, jdx += gap, idx += gap) {mx[idx] = EvaluatorUtils::scaleUpToZZ(uvals[i].real(), logp);mx[jdx] = EvaluatorUtils::scaleUpToZZ(uvals[i].imag(), logp);}delete[] uvals;
}void Ring::encode(ZZ* mx, complex<double>* vals, long slots, long logp) {complex<double>* uvals = new complex<double> [slots];long i, jdx, idx;copy(vals, vals + slots, uvals);long gap = Nh / slots;EMBInv(uvals, slots);for (i = 0, jdx = Nh, idx = 0; i < slots; ++i, jdx += gap, idx += gap) {mx[idx] = EvaluatorUtils::scaleUpToZZ(uvals[i].real(), logp);mx[jdx] = EvaluatorUtils::scaleUpToZZ(uvals[i].imag(), logp);}delete[] uvals;
}void Ring::decode(ZZ* mx, complex<double>* vals, long slots, long logp, long logq) {ZZ q = qpows[logq];long gap = Nh / 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;vals[i].real(EvaluatorUtils::scaleDownToReal(tmp, logp));rem(tmp, mx[idx + Nh], q);if (NumBits(tmp) == logq) tmp -= q;vals[i].imag(EvaluatorUtils::scaleDownToReal(tmp, logp));}EMB(vals, slots);
}void Ring::addBootContext(long logSlots, long logp) {if (bootContextMap.find(logSlots) == bootContextMap.end()) {long slots = 1 << logSlots;long dslots = slots << 1;long logk = logSlots >> 1;long k = 1 << logk;long i, pos, ki, jdx, idx, deg;long gap = Nh >> logSlots;long np;uint64_t** rpvec = new uint64_t*[slots];uint64_t** rpvecInv = new uint64_t*[slots];uint64_t* rp1;uint64_t* rp2;long* bndvec = new long[slots];long* bndvecInv = new long[slots];long bnd1;long bnd2;ZZ* pvec = new ZZ[N];complex<double>* pvals = new complex<double> [dslots];double c = 0.25 / M_PI;if (logSlots < logNh) {long dgap = gap >> 1;for (ki = 0; ki < slots; ki += k) {for (pos = ki; pos < ki + k; ++pos) {for (i = 0; i < slots - pos; ++i) {deg = ((M - rotGroup[i + pos]) * i * gap) % M;pvals[i] = ksiPows[deg];pvals[i + slots].real(-pvals[i].imag());pvals[i + slots].imag(pvals[i].real());}for (i = slots - pos; i < slots; ++i) {deg = ((M - rotGroup[i + pos - slots]) * i * gap) % M;pvals[i] = ksiPows[deg];pvals[i + slots].real(-pvals[i].imag());pvals[i + slots].imag(pvals[i].real());}EvaluatorUtils::rightRotateAndEqual(pvals, dslots, ki);EMBInv(pvals, dslots);for (i = 0, jdx = Nh, idx = 0; i < dslots; ++i, jdx += dgap, idx += dgap) {pvec[idx] = EvaluatorUtils::scaleUpToZZ(pvals[i].real(), logp);pvec[jdx] = EvaluatorUtils::scaleUpToZZ(pvals[i].imag(), logp);}bndvec[pos] = maxBits(pvec, N);np = ceil((bndvec[pos] + logQ + 2 * logN + 2)/(double)pbnd);rpvec[pos] = new uint64_t[np << logN];CRT(rpvec[pos], pvec, np);for (i = 0; i < N; ++i) {pvec[i] = ZZ::zero();}}}for (i = 0; i < slots; ++i) {pvals[i] = 0.0;pvals[i + slots].real(0);pvals[i + slots].imag(-c);}EMBInv(pvals, dslots);for (i = 0, jdx = Nh, idx = 0; i < dslots; ++i, jdx += dgap, idx += dgap) {pvec[idx] = EvaluatorUtils::scaleUpToZZ(pvals[i].real(), logp);pvec[jdx] = EvaluatorUtils::scaleUpToZZ(pvals[i].imag(), logp);}bnd1 = maxBits(pvec, N);np = ceil((bnd1 + logQ + 2 * logN + 2)/(double)pbnd);rp1 = new uint64_t[np << logN];CRT(rp1, pvec, np);for (i = 0; i < N; ++i) {pvec[i] = ZZ::zero();}for (i = 0; i < slots; ++i) {pvals[i] = c;pvals[i + slots] = 0;}EMBInv(pvals, dslots);for (i = 0, jdx = Nh, idx = 0; i < dslots; ++i, jdx += dgap, idx += dgap) {pvec[idx] = EvaluatorUtils::scaleUpToZZ(pvals[i].real(), logp);pvec[jdx] = EvaluatorUtils::scaleUpToZZ(pvals[i].imag(), logp);}bnd2 = maxBits(pvec, N);np = ceil((bnd2 + logQ + 2 * logN + 2)/(double)pbnd);rp2 = new uint64_t[np << logN];CRT(rp2, pvec, np);for (i = 0; i < N; ++i) {pvec[i] = ZZ::zero();}} else {for (ki = 0; ki < slots; ki += k) {for (pos = ki; pos < ki + k; ++pos) {for (i = 0; i < slots - pos; ++i) {deg = ((M - rotGroup[i + pos]) * i * gap) % M;pvals[i] = ksiPows[deg];}for (i = slots - pos; i < slots; ++i) {deg = ((M - rotGroup[i + pos - slots]) * i * gap) % M;pvals[i] = ksiPows[deg];}EvaluatorUtils::rightRotateAndEqual(pvals, slots, ki);EMBInv(pvals, slots);for (i = 0, jdx = Nh, idx = 0; i < slots; ++i, jdx += gap, idx += gap) {pvec[idx] = EvaluatorUtils::scaleUpToZZ(pvals[i].real(), logp);pvec[jdx] = EvaluatorUtils::scaleUpToZZ(pvals[i].imag(), logp);}bndvec[pos] = maxBits(pvec, N);np = ceil((bndvec[pos] + logQ + 2 * logN + 2)/(double)pbnd);rpvec[pos] = new uint64_t[np << logN];CRT(rpvec[pos], pvec, np);for (i = 0; i < N; ++i) {pvec[i] = ZZ::zero();}}}}for (ki = 0; ki < slots; ki += k) {for (pos = ki; pos < ki + k; ++pos) {for (i = 0; i < slots - pos; ++i) {deg = (rotGroup[i] * (i + pos) * gap) % M;pvals[i] = ksiPows[deg];}for (i = slots - pos; i < slots; ++i) {deg = (rotGroup[i] * (i + pos - slots) * gap) % M;pvals[i] = ksiPows[deg];}EvaluatorUtils::rightRotateAndEqual(pvals, slots, ki);EMBInv(pvals, slots);for (i = 0, jdx = Nh, idx = 0; i < slots;++i, jdx += gap, idx += gap) {pvec[idx] = EvaluatorUtils::scaleUpToZZ(pvals[i].real(), logp);pvec[jdx] = EvaluatorUtils::scaleUpToZZ(pvals[i].imag(), logp);}bndvecInv[pos] = maxBits(pvec, N);np = ceil((bndvecInv[pos] + logQ + 2 * logN + 2)/(double)pbnd);rpvecInv[pos] = new uint64_t[np << logN];CRT(rpvecInv[pos], pvec, np);for (i = 0; i < N; ++i) {pvec[i] = ZZ::zero();}}}delete[] pvals;delete[] pvec;bootContextMap.insert(pair<long, BootContext*>(logSlots, new BootContext(rpvec, rpvecInv, rp1, rp2, bndvec, bndvecInv, bnd1, bnd2, logp)));}
}//----------------------------------------------------------------------------------
//   MULTIPLICATION
//----------------------------------------------------------------------------------long Ring::maxBits(const ZZ* f, long n) {long i, m;m = 0;for (i = 0; i < n; i++) {m = max(m, NumBits(f[i]));}return m;
}void Ring::CRT(uint64_t* rx, ZZ* x, const long np) {multiplier.CRT(rx, x, np);
}void Ring::addNTTAndEqual(uint64_t* ra, uint64_t* rb, const long np) {multiplier.addNTTAndEqual(ra, rb, np);
}void Ring::mult(ZZ* x, ZZ* a, ZZ* b, long np, const ZZ& q) {multiplier.mult(x, a, b, np, q);
}void Ring::multNTT(ZZ* x, ZZ* a, uint64_t* rb, long np, const ZZ& q) {multiplier.multNTT(x, a, rb, np, q);
}void Ring::multDNTT(ZZ* x, uint64_t* ra, uint64_t* rb, long np, const ZZ& q) {multiplier.multDNTT(x, ra, rb, np, q);
}void Ring::multAndEqual(ZZ* a, ZZ* b, long np, const ZZ& q) {multiplier.multAndEqual(a, b, np, q);
}void Ring::multNTTAndEqual(ZZ* a, uint64_t* rb, long np, const ZZ& q) {multiplier.multNTTAndEqual(a, rb, np, q);
}void Ring::square(ZZ* x, ZZ* a, long np, const ZZ& q) {multiplier.square(x, a, np, q);
}void Ring::squareNTT(ZZ* x, uint64_t* ra, long np, const ZZ& q) {multiplier.squareNTT(x, ra, np, q);
}void Ring::squareAndEqual(ZZ* a, long np, const ZZ& q) {multiplier.squareAndEqual(a, np, q);
}//----------------------------------------------------------------------------------
//   OTHER
//----------------------------------------------------------------------------------void Ring::mod(ZZ* res, ZZ* p, const ZZ& mod) {for (long i = 0; i < N; ++i) {res[i] = p[i] % mod;}
}void Ring::modAndEqual(ZZ* p, const ZZ& mod) {for (long i = 0; i < N; ++i) {p[i] %= mod;}
}void Ring::negate(ZZ* res, ZZ* p) {for (long i = 0; i < N; ++i) {res[i] = -p[i];}
}void Ring::negateAndEqual(ZZ* p) {for (long i = 0; i < N; ++i) {p[i] = -p[i];}
}void Ring::add(ZZ* res, ZZ* p1, ZZ* p2, const ZZ& mod) {for (long i = 0; i < N; ++i) {AddMod(res[i], p1[i], p2[i], mod);}
}void Ring::addAndEqual(ZZ* p1, ZZ* p2, const ZZ& mod) {for (long i = 0; i < N; ++i) {AddMod(p1[i], p1[i], p2[i], mod);}
}void Ring::sub(ZZ* res, ZZ* p1, ZZ* p2, const ZZ& mod) {for (long i = 0; i < N; ++i) {AddMod(res[i], p1[i], -p2[i], mod);}
}void Ring::subAndEqual(ZZ* p1, ZZ* p2, const ZZ& mod) {for (long i = 0; i < N; ++i) {AddMod(p1[i], p1[i], -p2[i], mod);}
}void Ring::subAndEqual2(ZZ* p1, ZZ* p2, const ZZ& mod) {for (long i = 0; i < N; ++i) {AddMod(p2[i], p1[i], -p2[i], mod);}
}void Ring::multByMonomial(ZZ* res, ZZ* p, long monomialDeg) {long shift = monomialDeg % M;if (shift == 0) {for (long i = 0; i < N; ++i) {res[i] = p[i];}} else {ZZ* tmpx = new ZZ[N];if (shift < N) {for (long i = 0; i < N; ++i) {tmpx[i] = p[i];}} else {for (long i = 0; i < N; ++i) {tmpx[i] = -p[i];}}shift %= N;for (long i = 0; i < shift; ++i) {res[i] = -tmpx[N - shift + i];}for (long i = shift; i < N; ++i) {res[i] = tmpx[i - shift];}delete[] tmpx;}
}void Ring::multByMonomialAndEqual(ZZ* p, long monomialDeg) {long shift = monomialDeg % M;if (shift == 0) {return;}ZZ* tmpx = new ZZ[N];if (shift < N) {for (long i = 0; i < N; ++i) {tmpx[i] = p[i];}} else {for (long i = 0; i < N; ++i) {tmpx[i] = -p[i];}}shift %= N;for (long i = 0; i < shift; ++i) {p[i] = -tmpx[N - shift + i];}for (long i = shift; i < N; ++i) {p[i] = tmpx[i - shift];}delete[] tmpx;
}void Ring::multByConst(ZZ* res, ZZ* p, ZZ& cnst, const ZZ& mod) {for (long i = 0; i < N; ++i) {MulMod(res[i], p[i], cnst, mod);}
}void Ring::multByConstAndEqual(ZZ* p, ZZ& cnst, const ZZ& mod) {for (long i = 0; i < N; ++i) {MulMod(p[i], p[i], cnst, mod);}
}void Ring::leftShift(ZZ* res, ZZ* p, const long bits, const ZZ& mod) {for (long i = 0; i < N; ++i) {res[i] = p[i] << bits;res[i] %= mod;}
}void Ring::leftShiftAndEqual(ZZ* p, const long bits, const ZZ& mod) {for (long i = 0; i < N; ++i) {p[i] <<= bits;p[i] %= mod;}
}void Ring::doubleAndEqual(ZZ* p, const ZZ& mod) {for (long i = 0; i < N; ++i) {p[i] <<= 1;p[i] %= mod;}
}void Ring::rightShift(ZZ* res, ZZ* p, long bits) {ZZ tmp = to_ZZ(1) << (bits - 1);for (long i = 0; i < N; ++i) {if (p[i]>0) res[i] = (p[i] + tmp) >> bits;else res[i] = (p[i] - tmp) >> bits;}
}void Ring::rightShiftAndEqual(ZZ* p, long bits) {ZZ tmp = to_ZZ(1) << (bits - 1);for (long i = 0; i < N; ++i) {if (p[i]>0) p[i] += tmp;else p[i] -= tmp;p[i] >>= bits;}
}//----------------------------------------------------------------------------------
//   ROTATION & CONJUGATION
//----------------------------------------------------------------------------------void Ring::leftRotate(ZZ* res, ZZ* p, long r) {long pow = rotGroup[r];for (long i = 0; i < N; ++i) {long ipow = i * pow;long shift = ipow % M;if (shift < N) {res[shift] = p[i];} else {res[shift - N] = -p[i];}}
}void Ring::conjugate(ZZ* res, ZZ* p) {res[0] = p[0];for (long i = 1; i < N; ++i) {res[i] = -p[N - i];}
}//----------------------------------------------------------------------------------
//   SAMPLING
//----------------------------------------------------------------------------------void Ring::subFromGaussAndEqual(ZZ* res, const ZZ& q) {static double Pi = 4.0 * atan(1.0);static long bignum = 0xfffffff;for (long i = 0; i < N; 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)) * sigma;AddMod(res[i], -res[i], (long) floor(rr * cos(theta) + 0.5), q);AddMod(res[i + 1], -res[i + 1], (long) floor(rr * sin(theta) + 0.5), q);}
}void Ring::subFromGaussAndEqual(ZZ* res, const ZZ& q, double _sigma) {static double Pi = 4.0 * atan(1.0);static long bignum = 0xfffffff;for (long i = 0; i < N; 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)) * _sigma;AddMod(res[i], -res[i], (long) floor(rr * cos(theta) + 0.5), q);AddMod(res[i + 1], -res[i + 1], (long) floor(rr * sin(theta) + 0.5), q);}
}void Ring::addGaussAndEqual(ZZ* res, const ZZ& q) {static double Pi = 4.0 * atan(1.0);static long bignum = 0xfffffff;for (long i = 0; i < N; 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)) * sigma;AddMod(res[i], res[i], (long) floor(rr * cos(theta) + 0.5), q);AddMod(res[i + 1], res[i + 1], (long) floor(rr * sin(theta) + 0.5), q);}
}void Ring::addGaussAndEqual(ZZ* res, const ZZ& q, double _sigma) {static double Pi = 4.0 * atan(1.0);static long bignum = 0xfffffff;for (long i = 0; i < N; 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)) * _sigma;AddMod(res[i], res[i], (long) floor(rr * cos(theta) + 0.5), q);AddMod(res[i + 1], res[i + 1], (long) floor(rr * sin(theta) + 0.5), q);}
}void Ring::sampleHWT(ZZ* res) {long idx = 0;ZZ tmp = RandomBits_ZZ(h);while(idx < h) {long i = RandomBits_long(logN);if(res[i] == 0) {res[i] = (bit(tmp, idx) == 0) ? ZZ(1) : ZZ(-1);idx++;}}
}void Ring::sampleZO(ZZ* res) {ZZ tmp = RandomBits_ZZ(M);for (long i = 0; i < N; ++i) {res[i] = (bit(tmp, 2 * i) == 0) ? ZZ(0) : (bit(tmp, 2 * i + 1) == 0) ? ZZ(1) : ZZ(-1);}
}void Ring::sampleUniform2(ZZ* res, long bits) {for (long i = 0; i < N; i++) {res[i] = RandomBits_ZZ(bits);}
}}  // namespace heaan

RingMultiplier.h

#ifndef HEAAN_RINGMULTIPLIER_H_
#define HEAAN_RINGMULTIPLIER_H_#include <cstdint>
#include <vector>
#include <NTL/ZZ.h>
#include "Params.h"namespace heaan {class RingMultiplier {public:uint64_t* pVec = new uint64_t[nprimes];uint64_t* prVec = new uint64_t[nprimes];uint64_t* pInvVec = new uint64_t[nprimes];uint64_t** scaledRootPows = new uint64_t*[nprimes];uint64_t** scaledRootInvPows = new uint64_t*[nprimes];uint64_t* scaledNInv = new uint64_t[nprimes];_ntl_general_rem_one_struct* red_ss_array[nprimes];NTL::mulmod_precon_t* coeffpinv_array[nprimes];NTL::ZZ* pProd = new NTL::ZZ[nprimes];NTL::ZZ* pProdh = new NTL::ZZ[nprimes];NTL::ZZ** pHat = new NTL::ZZ*[nprimes];uint64_t** pHatInvModp = new uint64_t*[nprimes];RingMultiplier();bool primeTest(uint64_t p);void NTT(uint64_t* a, long index);void INTT(uint64_t* a, long index);void CRT(uint64_t* rx, NTL::ZZ* x, const long np);void addNTTAndEqual(uint64_t* ra, uint64_t* rb, const long np);void reconstruct(NTL::ZZ* x, uint64_t* rx, long np, const NTL::ZZ& QQ);void mult(NTL::ZZ* x, NTL::ZZ* a, NTL::ZZ* b, long np, const NTL::ZZ& QQ);void multNTT(NTL::ZZ* x, NTL::ZZ* a, uint64_t* rb, long np, const NTL::ZZ& QQ);void multDNTT(NTL::ZZ* x, uint64_t* ra, uint64_t* rb, long np, const NTL::ZZ& QQ);void multAndEqual(NTL::ZZ* a, NTL::ZZ* b, long np, const NTL::ZZ& QQ);void multNTTAndEqual(NTL::ZZ* a, uint64_t* rb, long np, const NTL::ZZ& QQ);void square(NTL::ZZ* x, NTL::ZZ* a, long np, const NTL::ZZ& QQ);void squareNTT(NTL::ZZ* x, uint64_t* ra, long np, const NTL::ZZ& QQ);void squareAndEqual(NTL::ZZ* a, long np, const NTL::ZZ& QQ);void mulMod(uint64_t& r, uint64_t a, uint64_t b, uint64_t p);void mulModBarrett(uint64_t& r, uint64_t a, uint64_t b, uint64_t p, uint64_t pr);void butt(uint64_t& a, uint64_t& b, uint64_t W, uint64_t p, uint64_t pInv);void ibutt(uint64_t& a, uint64_t& b, uint64_t W, uint64_t p, uint64_t pInv);void idivN(uint64_t& a, uint64_t NScale, uint64_t p, uint64_t pInv);uint64_t invMod(uint64_t x, uint64_t p);uint64_t powMod(uint64_t x, uint64_t y, uint64_t p);uint64_t inv(uint64_t x);uint64_t pow(uint64_t x, uint64_t y);uint32_t bitReverse(uint32_t x);void findPrimeFactors(std::vector<uint64_t> &s, uint64_t number);uint64_t findPrimitiveRoot(uint64_t m);uint64_t findMthRootOfUnity(uint64_t M, uint64_t p);};}  // namespace heaan#endif /* RINGMULTIPLIER_H_ */

RingMultiplier.cpp

#include "RingMultiplier.h"#include <NTL/BasicThreadPool.h>
#include <NTL/tools.h>
#include <cmath>
#include <cstdlib>
#include <iterator>using namespace std;
using namespace NTL;namespace heaan {RingMultiplier::RingMultiplier() {uint64_t primetest = (1ULL << pbnd) + 1;for (long i = 0; i < nprimes; ++i) {while(true) {primetest += M;if(primeTest(primetest)) {pVec[i] = primetest;break;}}}for (long i = 0; i < nprimes; ++i) {red_ss_array[i] = _ntl_general_rem_one_struct_build(pVec[i]);pInvVec[i] = inv(pVec[i]);prVec[i] = (static_cast<unsigned __int128>(1) << kbar2) / pVec[i];uint64_t root = findMthRootOfUnity(M, pVec[i]);uint64_t rootinv = invMod(root, pVec[i]);uint64_t NInv = invMod(N, pVec[i]);mulMod(scaledNInv[i], NInv, (1ULL << 32), pVec[i]);mulMod(scaledNInv[i], scaledNInv[i], (1ULL << 32), pVec[i]);scaledRootPows[i] = new uint64_t[N]();scaledRootInvPows[i] = new uint64_t[N]();uint64_t power = 1;uint64_t powerInv = 1;for (long j = 0; j < N; ++j) {uint32_t jprime = bitReverse(static_cast<uint32_t>(j)) >> (32 - logN);uint64_t rootpow = power;mulMod(scaledRootPows[i][jprime], rootpow,(1ULL << 32), pVec[i]);mulMod(scaledRootPows[i][jprime], scaledRootPows[i][jprime], (1ULL << 32), pVec[i]);uint64_t rootpowInv = powerInv;mulMod(scaledRootInvPows[i][jprime], rootpowInv, (1ULL << 32), pVec[i]);mulMod(scaledRootInvPows[i][jprime], scaledRootInvPows[i][jprime], (1ULL << 32), pVec[i]);mulMod(power, power, root, pVec[i]);mulMod(powerInv, powerInv, rootinv, pVec[i]);}}for (long i = 0; i < nprimes; ++i) {coeffpinv_array[i] = new mulmod_precon_t[i + 1];pProd[i] = (i == 0) ? to_ZZ((long) pVec[i]) : pProd[i - 1] * (long) pVec[i];pProdh[i] = pProd[i] / 2;pHat[i] = new ZZ[i + 1];pHatInvModp[i] = new uint64_t[i + 1];for (long j = 0; j < i + 1; ++j) {pHat[i][j] = ZZ(1);for (long k = 0; k < j; ++k) {pHat[i][j] *= (long) pVec[k];}for (long k = j + 1; k < i + 1; ++k) {pHat[i][j] *= (long) pVec[k];}pHatInvModp[i][j] = to_long(pHat[i][j] % (long) pVec[j]);pHatInvModp[i][j] = invMod(pHatInvModp[i][j], pVec[j]);coeffpinv_array[i][j] = PrepMulModPrecon(pHatInvModp[i][j], pVec[j]);}}
}bool RingMultiplier::primeTest(uint64_t p) {if(p < 2) return false;if(p != 2 && p % 2 == 0) return false;uint64_t s = p - 1;while(s % 2 == 0) {s /= 2;}for(long i = 0; i < 200; i++) {uint64_t temp1 = rand();temp1  = (temp1 << 32) | rand();temp1 = temp1 % (p - 1) + 1;uint64_t temp2 = s;uint64_t mod = powMod(temp1,temp2,p);while (temp2 != p - 1 && mod != 1 && mod != p - 1) {mulMod(mod, mod, mod, p);temp2 *= 2;}if (mod != p - 1 && temp2 % 2 == 0) return false;}return true;
}void RingMultiplier::NTT(uint64_t* a, long index) {long t = N;long logt1 = logN + 1;uint64_t p = pVec[index];uint64_t pInv = pInvVec[index];for (long m = 1; m < N; m <<= 1) {t >>= 1;logt1 -= 1;for (long i = 0; i < m; i++) {long j1 = i << logt1;long j2 = j1 + t - 1;uint64_t W = scaledRootPows[index][m + i];for (long j = j1; j <= j2; j++) {butt(a[j], a[j+t], W, p, pInv);}}}
}void RingMultiplier::INTT(uint64_t* a, long index) {uint64_t p = pVec[index];uint64_t pInv = pInvVec[index];long t = 1;for (long m = N; m > 1; m >>= 1) {long j1 = 0;long h = m >> 1;for (long i = 0; i < h; i++) {long j2 = j1 + t - 1;uint64_t W = scaledRootInvPows[index][h + i];for (long j = j1; j <= j2; j++) {ibutt(a[j], a[j+t], W, p, pInv);}j1 += (t << 1);}t <<= 1;}uint64_t NScale = scaledNInv[index];for (long i = 0; i < N; i++) {idivN(a[i], NScale, p, pInv);}
}//----------------------------------------------------------------------------------
//   FFT
//----------------------------------------------------------------------------------void RingMultiplier::CRT(uint64_t* rx, ZZ* x, const long np) {NTL_EXEC_RANGE(np, first, last);for (long i = first; i < last; ++i) {uint64_t* rxi = rx + (i << logN);uint64_t pi = pVec[i];_ntl_general_rem_one_struct* red_ss = red_ss_array[i];for (long n = 0; n < N; ++n) {rxi[n] = _ntl_general_rem_one_struct_apply(x[n].rep, pi, red_ss);}NTT(rxi, i);}NTL_EXEC_RANGE_END;
}void RingMultiplier::addNTTAndEqual(uint64_t* ra, uint64_t* rb, const long np) {for (long i = 0; i < np; ++i) {uint64_t* rai = ra + (i << logN);uint64_t* rbi = rb + (i << logN);uint64_t pi = pVec[i];for (long n = 0; n < N; ++n) {rai[n] += rbi[n];if(rai[n] > pi) rai[n] -= pi;}}
}void RingMultiplier::reconstruct(ZZ* x, uint64_t* rx, long np, const ZZ& q) {ZZ* pHatnp = pHat[np - 1];uint64_t* pHatInvModpnp = pHatInvModp[np - 1];mulmod_precon_t* coeffpinv_arraynp = coeffpinv_array[np - 1];ZZ& pProdnp = pProd[np - 1];ZZ& pProdhnp = pProdh[np - 1];NTL_EXEC_RANGE(N, first, last);for (long n = first; n < last; ++n) {ZZ& acc = x[n];QuickAccumBegin(acc, pProdnp.size());for (long i = 0; i < np; i++) {long p = pVec[i];long tt = pHatInvModpnp[i];mulmod_precon_t ttpinv = coeffpinv_arraynp[i];long s = MulModPrecon(rx[n + (i << logN)], tt, p, ttpinv);QuickAccumMulAdd(acc, pHatnp[i], s);}QuickAccumEnd(acc);rem(x[n], x[n], pProdnp);if (x[n] > pProdhnp) x[n] -= pProdnp;x[n] %= q;}NTL_EXEC_RANGE_END;
}void RingMultiplier::mult(ZZ* x, ZZ* a, ZZ* b, long np, const ZZ& mod) {uint64_t* ra = new uint64_t[np << logN]();uint64_t* rb = new uint64_t[np << logN]();uint64_t* rx = new uint64_t[np << logN]();NTL_EXEC_RANGE(np, first, last);for (long i = first; i < last; ++i) {uint64_t* rai = ra + (i << logN);uint64_t* rbi = rb + (i << logN);uint64_t* rxi = rx + (i << logN);uint64_t pi = pVec[i];uint64_t pri = prVec[i];_ntl_general_rem_one_struct* red_ss = red_ss_array[i];for (long n = 0; n < N; ++n) {rai[n] = _ntl_general_rem_one_struct_apply(a[n].rep, pi, red_ss);rbi[n] = _ntl_general_rem_one_struct_apply(b[n].rep, pi, red_ss);}NTT(rai, i);NTT(rbi, i);for (long n = 0; n < N; ++n) {mulModBarrett(rxi[n], rai[n], rbi[n], pi, pri);}INTT(rxi, i);}NTL_EXEC_RANGE_END;reconstruct(x, rx, np, mod);delete[] ra;delete[] rb;delete[] rx;
}void RingMultiplier::multNTT(ZZ* x, ZZ* a, uint64_t* rb, long np, const ZZ& mod) {uint64_t* ra = new uint64_t[np << logN]();uint64_t* rx = new uint64_t[np << logN]();NTL_EXEC_RANGE(np, first, last);for (long i = first; i < last; ++i) {uint64_t* rai = ra + (i << logN);uint64_t* rbi = rb + (i << logN);uint64_t* rxi = rx + (i << logN);uint64_t pi = pVec[i];uint64_t pri = prVec[i];_ntl_general_rem_one_struct* red_ss = red_ss_array[i];for (long n = 0; n < N; ++n) {rai[n] = _ntl_general_rem_one_struct_apply(a[n].rep, pi, red_ss);}NTT(rai, i);for (long n = 0; n < N; ++n) {mulModBarrett(rxi[n], rai[n], rbi[n], pi, pri);}INTT(rxi, i);}NTL_EXEC_RANGE_END;reconstruct(x, rx, np, mod);delete[] ra;delete[] rx;
}void RingMultiplier::multDNTT(ZZ* x, uint64_t* ra, uint64_t* rb, long np, const ZZ& mod) {uint64_t* rx = new uint64_t[np << logN]();NTL_EXEC_RANGE(np, first, last);for (long i = first; i < last; ++i) {uint64_t* rai = ra + (i << logN);uint64_t* rbi = rb + (i << logN);uint64_t* rxi = rx + (i << logN);uint64_t pi = pVec[i];uint64_t pri = prVec[i];for (long n = 0; n < N; ++n) {mulModBarrett(rxi[n], rai[n], rbi[n], pi, pri);}INTT(rxi, i);}NTL_EXEC_RANGE_END;reconstruct(x, rx, np, mod);delete[] rx;
}void RingMultiplier::multAndEqual(ZZ* a, ZZ* b, long np, const ZZ& mod) {uint64_t* ra = new uint64_t[np << logN]();uint64_t* rb = new uint64_t[np << logN]();NTL_EXEC_RANGE(np, first, last);for (long i = first; i < last; ++i) {uint64_t* rai = ra + (i << logN);uint64_t* rbi = rb + (i << logN);uint64_t pi = pVec[i];uint64_t pri = prVec[i];_ntl_general_rem_one_struct* red_ss = red_ss_array[i];for (long n = 0; n < N; ++n) {rai[n] = _ntl_general_rem_one_struct_apply(a[n].rep, pi, red_ss);rbi[n] = _ntl_general_rem_one_struct_apply(b[n].rep, pi, red_ss);}NTT(rai, i);NTT(rbi, i);for (long n = 0; n < N; ++n) {mulModBarrett(rai[n], rai[n], rbi[n], pi, pri);}INTT(rai, i);}NTL_EXEC_RANGE_END;ZZ* pHatnp = pHat[np - 1];uint64_t* pHatInvModpnp = pHatInvModp[np - 1];reconstruct(a, ra, np, mod);delete[] ra;delete[] rb;
}void RingMultiplier::multNTTAndEqual(ZZ* a, uint64_t* rb, long np, const ZZ& mod) {uint64_t* ra = new uint64_t[np << logN]();NTL_EXEC_RANGE(np, first, last);for (long i = first; i < last; ++i) {uint64_t* rai = ra + (i << logN);uint64_t* rbi = rb + (i << logN);uint64_t pi = pVec[i];uint64_t pri = prVec[i];_ntl_general_rem_one_struct* red_ss = red_ss_array[i];for (long n = 0; n < N; ++n) {rai[n] = _ntl_general_rem_one_struct_apply(a[n].rep, pi, red_ss);}NTT(rai, i);for (long n = 0; n < N; ++n) {mulModBarrett(rai[n], rai[n], rbi[n], pi, pri);}INTT(rai, i);}NTL_EXEC_RANGE_END;ZZ* pHatnp = pHat[np - 1];uint64_t* pHatInvModpnp = pHatInvModp[np - 1];reconstruct(a, ra, np, mod);delete[] ra;
}void RingMultiplier::square(ZZ* x, ZZ* a, long np, const ZZ& mod) {uint64_t* ra = new uint64_t[np << logN]();uint64_t* rx = new uint64_t[np << logN]();NTL_EXEC_RANGE(np, first, last);for (long i = first; i < last; ++i) {uint64_t* rai = ra + (i << logN);uint64_t* rxi = rx + (i << logN);uint64_t pi = pVec[i];uint64_t pri = prVec[i];_ntl_general_rem_one_struct* red_ss = red_ss_array[i];for (long n = 0; n < N; ++n) {rai[n] = _ntl_general_rem_one_struct_apply(a[n].rep, pi, red_ss);}NTT(rai, i);for (long n = 0; n < N; ++n) {mulModBarrett(rxi[n], rai[n], rai[n], pi, pri);}INTT(rxi, i);}NTL_EXEC_RANGE_END;ZZ* pHatnp = pHat[np - 1];uint64_t* pHatInvModpnp = pHatInvModp[np - 1];reconstruct(x, rx, np, mod);delete[] ra;delete[] rx;
}void RingMultiplier::squareNTT(ZZ* x, uint64_t* ra, long np, const ZZ& mod) {uint64_t* rx = new uint64_t[np << logN]();NTL_EXEC_RANGE(np, first, last);for (long i = first; i < last; ++i) {uint64_t* rai = ra + (i << logN);uint64_t* rxi = rx + (i << logN);uint64_t pi = pVec[i];uint64_t pri = prVec[i];for (long n = 0; n < N; ++n) {mulModBarrett(rxi[n], rai[n], rai[n], pi, pri);}INTT(rxi, i);}NTL_EXEC_RANGE_END;reconstruct(x, rx, np, mod);delete[] rx;
}void RingMultiplier::squareAndEqual(ZZ* a, long np, const ZZ& mod) {uint64_t* ra = new uint64_t[np << logN]();NTL_EXEC_RANGE(np, first, last);for (long i = first; i < last; ++i) {uint64_t* rai = ra + (i << logN);uint64_t pi = pVec[i];uint64_t pri = prVec[i];_ntl_general_rem_one_struct* red_ss = red_ss_array[i];for (long n = 0; n < N; ++n) {rai[n] = _ntl_general_rem_one_struct_apply(a[n].rep, pi, red_ss);}NTT(rai, i);for (long n = 0; n < N; ++n) {mulModBarrett(rai[n], rai[n], rai[n], pi, pri);}INTT(rai, i);}NTL_EXEC_RANGE_END;reconstruct(a, ra, np, mod);delete[] ra;
}void RingMultiplier::mulMod(uint64_t &r, uint64_t a, uint64_t b, uint64_t m) {unsigned __int128 mul = static_cast<unsigned __int128>(a) * b;mul %= static_cast<unsigned __int128>(m);r = static_cast<uint64_t>(mul);
}void RingMultiplier::mulModBarrett(uint64_t& r, uint64_t a, uint64_t b, uint64_t p, uint64_t pr) {unsigned __int128 mul = static_cast<unsigned __int128>(a) * b;uint64_t abot = static_cast<uint64_t>(mul);uint64_t atop = static_cast<uint64_t>(mul >> 64);unsigned __int128 tmp = static_cast<unsigned __int128>(abot) * pr;tmp >>= 64;tmp += static_cast<unsigned __int128>(atop) * pr;tmp >>= kbar2 - 64;tmp *= p;tmp = mul - tmp;r = static_cast<uint64_t>(tmp);if(r >= p) r -= p;
}void RingMultiplier::butt(uint64_t& a, uint64_t& b, uint64_t W, uint64_t p, uint64_t pInv) {unsigned __int128 U = static_cast<unsigned __int128>(b) * W;uint64_t U0 = static_cast<uint64_t>(U);uint64_t U1 = U >> 64;uint64_t Q = U0 * pInv;unsigned __int128 Hx = static_cast<unsigned __int128>(Q) * p;uint64_t H = Hx >> 64;uint64_t V = U1 < H ? U1 + p - H : U1 - H;b = a < V ? a + p - V : a - V;a += V;if (a > p) a -= p;
}void RingMultiplier::ibutt(uint64_t& a, uint64_t& b, uint64_t W, uint64_t p, uint64_t pInv) {uint64_t T = a < b ? a + p - b : a - b;a += b;if (a > p) a -= p;unsigned __int128 UU = static_cast<unsigned __int128>(T) * W;uint64_t U0 = static_cast<uint64_t>(UU);uint64_t U1 = UU >> 64;uint64_t Q = U0 * pInv;unsigned __int128 Hx = static_cast<unsigned __int128>(Q) * p;uint64_t H = Hx >> 64;b = (U1 < H) ? U1 + p - H : U1 - H;
}void RingMultiplier::idivN(uint64_t& a, uint64_t NScale, uint64_t p, uint64_t pInv) {unsigned __int128 U = static_cast<unsigned __int128>(a) * NScale;uint64_t U0 = static_cast<uint64_t>(U);uint64_t U1 = U >> 64;uint64_t Q = U0 * pInv;unsigned __int128 Hx = static_cast<unsigned __int128>(Q) * p;uint64_t H = Hx >> 64;a = (U1 < H) ? U1 + p - H : U1 - H;
}uint64_t RingMultiplier::invMod(uint64_t x, uint64_t m) {return powMod(x, m - 2, m);
}uint64_t RingMultiplier::powMod(uint64_t x, uint64_t y, uint64_t modulus) {uint64_t res = 1;while (y > 0) {if (y & 1) {mulMod(res, res, x, modulus);}y = y >> 1;mulMod(x, x, x, modulus);}return res;
}uint64_t RingMultiplier::inv(uint64_t x) {return pow(x, static_cast<uint64_t>(-1));
}uint64_t RingMultiplier::pow(uint64_t x, uint64_t y) {uint64_t res = 1;while (y > 0) {if (y & 1) {res *= x;}y = y >> 1;x *= x;}return res;
}uint32_t RingMultiplier::bitReverse(uint32_t x) {x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));return ((x >> 16) | (x << 16));
}void RingMultiplier::findPrimeFactors(vector<uint64_t> &s, uint64_t number) {while (number % 2 == 0) {s.push_back(2);number /= 2;}for (uint64_t i = 3; i < sqrt(number); i++) {while (number % i == 0) {s.push_back(i);number /= i;}}if (number > 2) {s.push_back(number);}
}uint64_t RingMultiplier::findPrimitiveRoot(uint64_t modulus) {vector<uint64_t> s;uint64_t phi = modulus - 1;findPrimeFactors(s, phi);for (uint64_t r = 2; r <= phi; r++) {bool flag = false;for (auto it = s.begin(); it != s.end(); it++) {if (powMod(r, phi / (*it), modulus) == 1) {flag = true;break;}}if (flag == false) {return r;}}return -1;
}uint64_t RingMultiplier::findMthRootOfUnity(uint64_t M, uint64_t mod) {uint64_t res;res = findPrimitiveRoot(mod);if((mod - 1) % M == 0) {uint64_t factor = (mod - 1) / M;res = powMod(res, factor, mod);return res;}else {return -1;}
}}  // namespace heaan

HEAAN开源库源码(一)相关推荐

  1. SEAL开源库源码02

    SEAL开源库源码02 本篇的最终目的是要分析 seal/modulus.h 文章目录 SEAL开源库源码02 seal/version.h seal/util/hestdparms.h 128-bi ...

  2. SEAL开源库源码10

    SEAL开源库源码10 文章目录 SEAL开源库源码10 seal/evaluator.h Evaluator 类 构造函数,利用 context 来构造 negate_inplace 和 negat ...

  3. SEAL开源库源码12

    SEAL开源库源码12 文章目录 SEAL开源库源码12 5_ckks_basics.cpp example_ckks_basics 函数 6_rotation.cpp example_rotatio ...

  4. SEAL开源库源码01

    SEAL开源库源码01 文章目录 SEAL开源库源码01 seal/util/defines.h 通用的判断函数 将x输出为字符串 字符串的拼接 检查double类型是否是64比特 检查int是否为3 ...

  5. 【移动开发】Checkout开源库源码解析

    Checkout开源库的源码解析 1.功能介绍 1.1Checkout是什么 Checkout是Android In-App Billing API(v3 +)的一个封装库.In-App Billin ...

  6. 《安富莱嵌入式周报》第293期:SEGGER开源其C/C++库源码emRun,丰富EMC电磁兼容资,OTA开源组件,2022 Github全球报告,内存安全指南

    往期周报汇总地址:嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - P ...

  7. Android开源框架源码鉴赏:Fresco

    文章目录 一 图片加载流程 1.1 初始化Fresco 1.2 获取DataSource 1.3 绑定DraweeController与DraweeHierarchy 1.4 从内存缓存/磁盘缓存/网 ...

  8. android 三方_面试官送你一份Android热门三方库源码面试宝典及学习笔记

    前言 众所周知,优秀源码的阅读与理解是最能提升自身功力的途径,如果想要成为一名优秀的Android工程师,那么Android中优秀三方库源码的分析和理解则是必备技能.就拿比较热门的图片加载框架Glid ...

  9. 开源中国源码学习(六)——ButterKnife的使用

    本文翻译自 Butter Knife官方网站: ButterKnife 简介 用@Bind给字段进行注释并且Butter Knife会根据给定的View ID去查找并自动转换为与你的layout中相匹 ...

最新文章

  1. virtualbox 安装ubuntu 时,看不到继续、退出按钮?共享文件无权限?
  2. Qt/PyQt中使用系统全局的快捷键
  3. 用字典生成model的代码
  4. 如何通过反射调用扩展方法?
  5. 《数据结构》第01章在线测试
  6. CoderForces999D-Equalize the Remainders
  7. extjs的panel怎么自适应高度_Ext Js自适应高度
  8. 27.crontab
  9. 安装SQL Server 2016
  10. 安信可BT-02 Mesh组网的AT指令集
  11. python人流热力图_高德地图热力图插件实现人流量监控,如何实现人流数据实时刷新...
  12. 【前端GUI】—— 网站美工必须掌握的PS知识点思维导图
  13. 深圳医保社保的使用方法
  14. 访问yy直播页面点击播放无响应分析
  15. Android系统体系结构
  16. nyoj-239 月老的难题 (二分图匹配—匈牙利算法 网络流—Dinic算法)
  17. 现在想心平气和地过完一天,真的太难了!
  18. Git提交gitlab项目string) [], ParseException +FullyQualifiedErrorId :UnexpectedToken 异常,commit failed
  19. 使用P.L.A.N法提升执行力
  20. 传统企业数字转型,主要面临哪些问题?

热门文章

  1. QDUOJ 67 - 礼上往来(错排公式)
  2. Spring Security 官网文档学习
  3. stata统计分析及行业应用案例分析_数据分析之路——描述性统计分析和应用案例...
  4. 百度推广有哪些技巧方法?如何利用线上引流的方式做百度推广?
  5. 云顶之弈机器人法爆_云顶之弈有什么套路?
  6. 怎样更改linux的用户名
  7. linux nginx svn 安装
  8. 新冠病毒中招 | 第二天
  9. 金阳公益·金山杜仲文化基地揭牌暨捐赠仪式圆满举办
  10. Idea导入eclipse web项目404问题(webcontent)