HEAAN库学习
阅读原文时间:2022年02月12日阅读:3

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

1、地址这是最老的一版,对应的论文CKKS17

2、在1的基础上,实现了bootstarpping技术,对应的论文

3、在2的基础上,优化,效率更高!

有三个文件夹:lib、run、src

lib:存放依赖库(静态文件),需要生成静态库,具体安装和生成静态库参考:MAC上安装HEAAN库

run:里面有一个run.cpp文件,为测试文件

src:里面是主要代码文件

下面主要学习测试文件(run.cpp)中的几个方法

testEncodeBatch

测试复数向量的编/解码、加/解密

void TestScheme::testEncodeBatch(long logN, long logQ, long logp, long logSlots) {
/*
 * 功能:测试明文的编码和解码时间
 * 参数:logN(密文维数)、logQ(最大密文模数)、logp(精度,即小数位数)、logSlots(明文插槽数,即多少个明文数能打包成一个明文多项式)
 */
    cout << "!!! START TEST ENCODE BATCH !!!" << endl;
    //-----------------------------------------
    TimeUtils timeutils;
    //初始化参数
    Context context(logN, logQ);
    //生成私钥
    SecretKey secretKey(logN);
    //生成公钥、计算密钥
    Scheme scheme(secretKey, context);
    //-----------------------------------------
    SetNumThreads(1);
    //-----------------------------------------
    srand(time(NULL));
    //-----------------------------------------
    //随机生成复数向量(含有实部和虚部)
    long slots = (1 << logSlots);
    complex<double>* mvec = EvaluatorUtils::randomComplexArray(slots);

    timeutils.start("Encrypt batch");
    //开始加密:将复数向量编码为消息,然后使用公钥将其加密成密文
    Ciphertext cipher = scheme.encrypt(mvec, slots, logp, logQ);
    timeutils.stop("Encrypt batch");

    timeutils.start("Decrypt batch");
    //开始解密:先解密,然后解密为复数向量
    complex<double>* dvec = scheme.decrypt(secretKey, cipher);
    timeutils.stop("Decrypt batch");
    //显示结果(成对):mval(复数向量)、dval(解密后的复数向量)、eval(误差)
    StringUtils::showcompare(mvec, dvec, slots, "val");

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

testBasic

测试复数向量的编/解码、加/解密、加/乘法

void TestScheme::testBasic(long logN, long logQ, long logp, long logSlots) {
    cout << "!!! START TEST BASIC !!!" << endl;
    //-----------------------------------------
    TimeUtils timeutils;
    Context context(logN, logQ);//参数初始化
    //密钥生成
    SecretKey secretKey(logN);//生成私钥
    Scheme scheme(secretKey, context);//生成公钥、计算密钥
    //-----------------------------------------
    SetNumThreads(1);
    //-----------------------------------------
    srand(time(NULL));
    //-----------------------------------------
    long slots = (1 << logSlots);//明文槽数
    //生成复数向量

    complex<double>* mvec1 = EvaluatorUtils::randomComplexArray(slots);
    complex<double>* mvec2 = EvaluatorUtils::randomComplexArray(slots);
    complex<double>* cvec = EvaluatorUtils::randomComplexArray(slots);

    //定义三个复数向量,用于存计算结果(明文)
    complex<double>* mvecAdd = new complex<double>[slots];
    complex<double>* mvecMult = new complex<double>[slots];
    complex<double>* mvecCMult = new complex<double>[slots];
    for(long i = 0; i < slots; i++) {
        mvecAdd[i] = mvec1[i] + mvec2[i];
        mvecMult[i] = mvec1[i] * mvec2[i];
        mvecCMult[i] = mvec1[i] * cvec[i];
    }
    timeutils.start("Encrypt two batch");
    Ciphertext cipher1 = scheme.encrypt(mvec1, slots, logp, logQ);
    Ciphertext cipher2 = scheme.encrypt(mvec2, slots, logp, logQ);
    timeutils.stop("Encrypt two batch");

    timeutils.start("Homomorphic Addition");
    Ciphertext addCipher = scheme.add(cipher1, cipher2);
    timeutils.stop("Homomorphic Addition");

    timeutils.start("Homomorphic Multiplication");//密文*密文呢
    Ciphertext multCipher = scheme.mult(cipher1, cipher2);//乘法
    scheme.reScaleByAndEqual(multCipher, logp);//重缩放
    timeutils.stop("Homomorphic Multiplication");

    timeutils.start("Homomorphic Multiplication");//密文*常量
    Ciphertext cmultCipher = scheme.multByConstVec(cipher1, cvec, slots, logp);//乘法
    scheme.reScaleByAndEqual(cmultCipher, logp);//重缩放
    timeutils.stop("Homomorphic Multiplication");

    timeutils.start("Decrypt batch");
    complex<double>* dvecAdd = scheme.decrypt(secretKey, addCipher);
    complex<double>* dvecMult = scheme.decrypt(secretKey, multCipher);
    complex<double>* dvecCMult = scheme.decrypt(secretKey, cmultCipher);
    timeutils.stop("Decrypt batch");

        cout <<"三个复数向量A、B、C:"<<endl;
        StringUtils::show(mvec1,slots);
        StringUtils::show(mvec2,slots);
        StringUtils::show(cvec,slots);
    StringUtils::showcompare(mvecAdd, dvecAdd, slots, "add");
    StringUtils::showcompare(mvecMult, dvecMult, slots, "mult");
    StringUtils::showcompare(mvecCMult, dvecCMult, slots, "mult");
}

参数

logN:N的对数,N是密文的维数

logQ:Q的对数,Q是最大密文模数

sigma:高斯分布的标准差

h:HWT的分布参数

N:是2的次幂,对应于环\(Z\left[ X \right]/\left( X^{N}+1 \right)\)

Nh = N/2,即明文模数

logNh = logN - 1

M = 2N

logQQ:PQ的对数

PQ = Q * Q

rotGroup:预计算的旋转组索引

ksiPows:

qpowvec:预计算2的幂

taylorCoeffsMap:预计算泰勒系数

构造函数

有两种,一种是逐个赋值,一种是快速赋值

//构造函数
Context::Context(long logN, long logQ, double sigma, long h) : logN(logN), logQ(logQ), sigma(sigma), h(h) {
    init(logN, logQ, sigma, h);
}

Context::Context(const Context& o) : logN(o.logN), logQ(o.logQ), sigma(o.sigma), h(o.h) {
    init(logN, logQ, sigma, h);
}

初始化

//初始化函数
void Context::init(long logN, long logQ, double sigma, long h) {
    N = 1 << logN; //求逆对数
    Nh = N >> 1;  //除2
    logNh = logN - 1;
    M = N << 1; //乘2
    logQQ = logQ << 1; //求对数
    Q = power2_ZZ(logQ); //求逆对数
    QQ = power2_ZZ(logQQ);//求逆对数

    rotGroup = new long[Nh]; //按顺序存储Nh个5的倍数(模 M)
    long fivePows = 1;
    for (long i = 0; i < Nh; ++i) {
        rotGroup[i] = fivePows;
        fivePows *= 5;
        fivePows %= M;
    }

    ksiPows = new complex<double>[M + 1];//存放的复数向量
    for (long j = 0; j < M; ++j) {
        double angle = 2.0 * M_PI * j / M;
        ksiPows[j].real(cos(angle));//实数部分
        ksiPows[j].imag(sin(angle));//虚数部分
    }

    ksiPows[M] = ksiPows[0];

    qpowvec = new ZZ[logQQ + 1];
    qpowvec[0] = ZZ(1);
    for (long i = 1; i < logQQ + 1; ++i) {
        qpowvec[i] = qpowvec[i - 1] << 1;
    }

    taylorCoeffsMap.insert(pair<string, double*>(LOGARITHM, new double[11]{0,1,-0.5,1./3,-1./4,1./5,-1./6,1./7,-1./8,1./9,-1./10}));
    taylorCoeffsMap.insert(pair<string, double*>(EXPONENT, new double[11]{1,1,0.5,1./6,1./24,1./120,1./720,1./5040, 1./40320,1./362880,1./3628800}));
    taylorCoeffsMap.insert(pair<string, double*>(SIGMOID, new double[11]{1./2,1./4,0,-1./48,0,1./480,0,-17./80640,0,31./1451520,0}));
}

析构函数

// 析构函数
Context::~Context() {
    delete[] rotGroup;
    delete[] ksiPows;
}

ZZ是什么类型,泰勒系数、如何生成复数向量的?

编码

ZZX Context::encode(complex<double>* vals, long slots, long logp) {
/*
 * 功能:将复数向量编码成多项式
 * 参数:vals(复数数组)、slots(数组大小)、logp(量化比特)
 */
    complex<double>* uvals = new complex<double>[slots]();
    long i, jdx, idx;
    copy(vals, vals + slots, uvals);

    ZZX mx;
    mx.SetLength(N);
    long gap = Nh / slots;
    fftSpecialInv(uvals, slots);
    for (i = 0, jdx = Nh, idx = 0; i < slots; ++i, jdx += gap, idx += gap) {
        mx.rep[idx] = EvaluatorUtils::scaleUpToZZ(uvals[i].real(), logp);
        mx.rep[jdx] = EvaluatorUtils::scaleUpToZZ(uvals[i].imag(), logp);
    }
    delete[] uvals;
    return mx;
}

ZZX Context::encodeSingle(complex<double> val, long logp) {
/*
 * 功能:将单个复数编码成多项式
 * 参数:vals(复数向量)、logp(量化比特)
 */
    ZZX mx;
    mx.SetLength(N);
    mx.rep[0] = EvaluatorUtils::scaleUpToZZ(val.real(), logp);
    mx.rep[Nh] = EvaluatorUtils::scaleUpToZZ(val.imag(), logp);
    return mx;
}

ZZX Context::encode(double* vals, long slots, long logp) {
/*
 * 功能:将多个数(浮点数组)编码成多项式
 * 参数:vals(浮点数组)、slots(数组大小)、logp(量化比特)
 */
    complex<double>* uvals = new complex<double>[slots];
    long i, jdx, idx;
    for (i = 0; i < slots; ++i) {
        uvals[i].real(vals[i]);
    }

    ZZX mx;
    mx.SetLength(N);

    long gap = Nh / slots;

    fftSpecialInv(uvals, slots);

    for (i = 0, jdx = Nh, idx = 0; i < slots; ++i, jdx += gap, idx += gap) {
        mx.rep[idx] = EvaluatorUtils::scaleUpToZZ(uvals[i].real(), logp);
        mx.rep[jdx] = EvaluatorUtils::scaleUpToZZ(uvals[i].imag(), logp);
    }
    delete[] uvals;
    return mx;
}

ZZX Context::encodeSingle(double val, long logp) {
/*
 * 功能:将单个数(浮点数)编码成多项式
 * 参数:vals(浮点数)、logp(量化比特)
 */
    ZZX mx;
    mx.SetLength(N);
    mx.rep[0] = EvaluatorUtils::scaleUpToZZ(val, logp);
    return mx;
}

解码

complex<double>* Context::decode(ZZX& mx, long slots, long logp, long logq) {
/*
 * 功能:将一个多项式解码为复数数组
 * 参数:mx(一个多项式)、slots(数组大小)、logp(量化比特)、logq(模数比特)
 */
    ZZ q = qpowvec[logq];
    long gap = Nh / slots;
    complex<double>* res = new complex<double>[slots];
    ZZ tmp;

    for (long i = 0, idx = 0; i < slots; ++i, idx += gap) {
        rem(tmp, mx[idx], q);
        if(NumBits(tmp) == logq) tmp -= q;
        res[i].real(EvaluatorUtils::scaleDownToReal(tmp, logp));

        rem(tmp, mx[idx + Nh], q);
        if(NumBits(tmp) == logq) tmp -= q;
        res[i].imag(EvaluatorUtils::scaleDownToReal(tmp, logp));
    }
    fftSpecial(res, slots);
    return res;
}

complex<double> Context::decodeSingle(ZZX& mx, long logp, long logq, bool isComplex) {
/*
 * 功能:将一个多项式解码为单个复数
 * 参数:mx(一个多项式)、logp(量化比特)、logq(模数比特)、isComplex(是否解码后是复数,默认是)
 */
    ZZ q = qpowvec[logq];

    complex<double> res;
    ZZ tmp = mx.rep[0] % q;
    if(NumBits(tmp) == logq) tmp -= q;
    res.real(EvaluatorUtils::scaleDownToReal(tmp, logp));

    if(isComplex) {
        tmp = mx.rep[Nh] % q;
        if(NumBits(tmp) == logq) tmp -= q;
        res.imag(EvaluatorUtils::scaleDownToReal(tmp, logp));
    }

    return res;
}

FFT

void Context::bitReverse(complex<double>* vals, const long size) {
/*
 * 功能:求FFT的比特置换(非)
 * 参数:vals(复数数组)、size(数组大小)
 */
    for (long i = 1, j = 0; i < size; ++i) {
        long bit = size >> 1;
        for (; j >= bit; bit>>=1) {
            j -= bit;
        }
        j += bit;
        if(i < j) {
            swap(vals[i], vals[j]);
        }
    }
}

void Context::fft(complex<double>* vals, const long size) {
/*
 * 功能:计算FFT在Z_q[X] / (X^N + 1)
 * 参数:vals(复数数组)、size(数组大小)
 */
    bitReverse(vals, size);
    for (long len = 2; len <= size; len <<= 1) {
        long MoverLen = M / len;
        long lenh = len >> 1;
        for (long i = 0; i < size; i += len) {
            for (long j = 0; j < lenh; ++j) {
                long idx = j * MoverLen;
                complex<double> u = vals[i + j];
                complex<double> v = vals[i + j + lenh];
                v *= ksiPows[idx];
                vals[i + j] = u + v;
                vals[i + j + lenh] = u - v;
            }
        }
    }
}

void Context::fftInvLazy(complex<double>* vals, const long size) {
/*
 * 功能:计算FFT的逆延迟
 * 参数:vals(复数数组)、size(数组大小)
 */
    bitReverse(vals, size);
    for (long len = 2; len <= size; len <<= 1) {
        long MoverLen = M / len;
        long lenh = len >> 1;
        for (long i = 0; i < size; i += len) {
            for (long j = 0; j < lenh; ++j) {
                long idx = (len - j) * MoverLen;
                complex<double> u = vals[i + j];
                complex<double> v = vals[i + j + lenh];
                v *= ksiPows[idx];
                vals[i + j] = u + v;
                vals[i + j + lenh] = u - v;
            }
        }
    }
}

void Context::fftInv(complex<double>* vals, const long size) {
/*
 * 功能:计算FFT的逆在Z_q[X] / (X^N + 1)
 * 参数:vals(复数数组)、size(数组大小)
 */
    fftInvLazy(vals, size);
    for (long i = 0; i < size; ++i) {
        vals[i] /= size;
    }
}

void Context::fftSpecial(complex<double>* vals, const long size) {
/*
 * 功能:在编码和解密时计算特殊FFT在Z_q[X] / (X^N + 1)
 * 参数:vals(复数数组)、size(数组大小)
 */
    bitReverse(vals, size);
    for (long len = 2; len <= size; len <<= 1) {
        for (long i = 0; i < size; i += len) {
            long lenh = len >> 1;
            long lenq = len << 2;
            for (long j = 0; j < lenh; ++j) {
                long idx = ((rotGroup[j] % lenq)) * M / lenq;
                complex<double> u = vals[i + j];
                complex<double> v = vals[i + j + lenh];
                v *= ksiPows[idx];
                vals[i + j] = u + v;
                vals[i + j + lenh] = u - v;
            }
        }
    }
}

void Context::fftSpecialInvLazy(complex<double>* vals, const long size) {
/*
 * 功能:在编码和解密时 计算特殊FFT逆的延迟 在Z_q[X] / (X^N + 1)
 * 参数:vals(复数数组)、size(数组大小)
 */
    for (long len = size; len >= 1; len >>= 1) {
        for (long i = 0; i < size; i += len) {
            long lenh = len >> 1;
            long lenq = len << 2;
            for (long j = 0; j < lenh; ++j) {
                long idx = (lenq - (rotGroup[j] % lenq)) * M / lenq;
                complex<double> u = vals[i + j] + vals[i + j + lenh];
                complex<double> v = vals[i + j] - vals[i + j + lenh];
                v *= ksiPows[idx];
                vals[i + j] = u;
                vals[i + j + lenh] = v;
            }
        }
    }
    bitReverse(vals, size);
}

void Context::fftSpecialInv(complex<double>* vals, const long size) {
/*
 * 功能:在编码和解密时 计算特殊FFT逆 在Z_q[X] / (X^N + 1)
 * 参数:vals(复数数组)、size(数组大小)
 */
    fftSpecialInvLazy(vals, size);
    for (long i = 0; i < size; ++i) {
        vals[i] /= size;
    }
}

关于FFT相关的知识,需要系统学习,后续整理出一篇文章!

参数

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) {}

密文是一个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) {}

多项式求模

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;
}

高斯采样

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是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) {}

参数

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);
}

旋转

用在编码时生成共轭复数时

序列化,将随机采样的明文、生成的密钥、密文、写入文件以及读取文件

数据采样,包括高斯采样等

参数

sx:私钥

构造函数

SecretKey::SecretKey(long logN, long h) {
    long N = 1 << logN; //求N
    NumUtils::sampleHWT(sx, N, h);//sx采样于HWT
}

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章