HElib:编译安装

参考文献:

  1. HElib 源码
  2. HEXL 源码
  3. googletest 源码
  4. bats-core 源码
  5. [HS13] Halevi S, Shoup V. Design and implementation of a homomorphic-encryption library[J]. IBM Research (Manuscript), 2013, 6(12-15): 8-36.
  6. [HS14] Halevi S, Shoup V. Algorithms in helib[C]//Advances in Cryptology–CRYPTO 2014: 34th Annual Cryptology Conference, Santa Barbara, CA, USA, August 17-21, 2014, Proceedings, Part I 34. Springer Berlin Heidelberg, 2014: 554-571.
  7. [HS15] Halevi S, Shoup V. Bootstrapping for helib[J]. Journal of Cryptology, 2021, 34(1): 7.
  8. [HS18] Halevi S, Shoup V. Faster homomorphic linear transformations in HElib[C]//Annual International Cryptology Conference. Cham: Springer International Publishing, 2018: 93-120.
  9. [HS20] Halevi S, Shoup V. Design and implementation of HElib: a homomorphic encryption library[J]. Cryptology ePrint Archive, 2020.
  10. 安装 GMP、NTL、CTMalloc
  11. 全同态加密:BGV
  12. 全同态加密:CKKS
  13. Full-RNS BGV/BFV
  14. FHE 的槽置换:Benes Network
  15. Level FHE 的快速算法:Double-CRT & Dot Multiplication
  16. 基于插值的同态比较算法 & Paterson-Stockmeyer 多项式求值算法

HElib

编译

配置环境,

sudo apt-get install patchelf #安装patchelf

cd ./googletest-main #编译安装gtest

cmake ./

sudo make && make install

cd ./bats-core-master #安装bats

sudo ./install.sh /usr/local lib64

安装 Intel/hexl 硬件加速库(我的 Intel® Core™ i9-12900H 不支持 AVX512 指令集,反而 Intel® Core™ i9-11900H 是支持的,本机查看 cat /proc/cpuinfo),

git config --global url."https://hub.nuaa.cf/".insteadOf "https://github.com/" #首先换个源,git 总是连不上 github

git clone --recurse-submodules https://github.com/intel/hexl.git/

cd ./hexl

cmake -S . -B build #配置 makefile,它会连接 github 拉取一些 cpu-features 文件

cmake --build build #编译 hexl

sudo cmake --install build #安装位置 install_manifest.txt

假如你的 NTL 依赖于 gf2x,那么还需要修改下 src/CMakeLists.txt(否则出现未定义函数),添加如下的编译配置:

add_compile_options(
  -lstdc++ -lm -lntl -pthread -lgf2x
)

find_package(gf2x)

......

target_link_libraries(helib gf2x)

正式编译,

mkdir build

cd ./build

cmake -DPACKAGE_BUILD=OFF -DENABLE_TEST=ON -DENABLE_THREADS=ON -DUSE_INTEL_HEXL=ON -DGMP_DIR="${GMPDIR}" -DNTL_DIR="${NTLDIR}" .. #开启一些选项,使用 hexl 需要关闭 PACKAGE_BUILD 选项

make -j 16 #多线程编译, build/helib_pack

ctest #测试编译是否正确, build/xunit_test_result

sudo make install #安装到计算机

详细安装信息查看 install_manifest.txt,因为 HElib 没有编写 make uninstall,可以使用命令 xargs rm < install_manifest.txt 简单删除文件来卸载。

示例

编译示例

cd /examples

mkdir build

cd ./build

cmake ..

make

运行 CKKS 用例:

>>> bin/01_ckks_basics

securityLevel=157.866
distance=3.15527e-06

>>> bin/02_ckks_depth

securityLevel=129.741
c.capacity=328.497 c.errorBound=1.28242e-06
c.capacity=289.748 c.errorBound=2.69368e-06
c.capacity=252.063 c.errorBound=5.73764e-06
c.capacity=213.502 c.errorBound=1.16416e-05
c.capacity=176.579 c.errorBound=2.37458e-05
c.capacity=139.634 c.errorBound=4.79519e-05
distance=4.17908e-05

>>> bin/03_ckks_data_movement

securityLevel=129.741
c.capacity=318.497 c.errorBound=1.25236e-09
c.capacity=310.254 c.errorBound=6.4202e-09
c.capacity=310.254 c.errorBound=1.64714e-08
c.capacity=271.254 c.errorBound=1.71435e-08
c.capacity=232.254 c.errorBound=1.78156e-08
c.capacity=219.254 c.errorBound=0.000145946
distance=0.000135014
GOOD

运行 BGV 用例:

>>> bin/BGV_packed_arithmetic

Initialising context object...
m = 32109, p = 4999, phi(m) = 16560
  ord(p) = 690
  normBnd = 2.32723
  polyNormBnd = 58.2464
  factors = [3 7 11 139]
  generator 320 has order (== Z_m^*) of 6
  generator 3893 has order (== Z_m^*) of 2
  generator 14596 has order (== Z_m^*) of 2
  T = [ 1 14596 3893 21407 320 14915 25618 11023 6073 20668 9965 27479 16820 31415 10009 27523 20197 2683 24089 9494 9131 23726 2320 19834 ]
r = 1
nslots = 24
hwt = 0
ctxtPrimes = [6,7,8,9,10,11,12,13,14]
specialPrimes = [15,16,17,18,19]
number of bits = 773

security level = 62.4783

Security: 62.4783
Creating secret key...
Generating key-switching matrices...
Number of slots: 24
Initial Plaintext: {"HElibVersion":"2.2.0","content":{"scheme":"BGV","slots":[[0],[1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],[14],[15],[16],[17],[18],[19],[20],[21],[22],[23]]},"serializationVersion":"0.0.1","type":"Ptxt"}
Operation: 2(a*a)/(a*a) - 2(a*a)/(a*a) = 0
Decrypted Result: {"HElibVersion":"2.2.0","content":{"scheme":"BGV","slots":[[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0]]},"serializationVersion":"0.0.1","type":"Ptxt"}
Plaintext Result: {"HElibVersion":"2.2.0","content":{"scheme":"BGV","slots":[[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0]]},"serializationVersion":"0.0.1","type":"Ptxt"}
Operation: Enc{(0 + 1)*1} + (0 + 1)*1
Decrypted Result: {"HElibVersion":"2.2.0","content":{"scheme":"BGV","slots":[[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2]]},"serializationVersion":"0.0.1","type":"Ptxt"}

除了 ./examples 中介绍基本用法,./tests 中其实有更详细的示例。

算法模块

HElib 的各个结构好复杂啊,./example 给的例子太简单了,编写工程代码需要更多的接口。花了两天时间翻看 ./include./src 源码,记录下它们的结构和接口。文章 [HS13] 解释了某些结构的设计原理。

在这里插入图片描述

Math Layer

NumbTh.h

实现了许多有用的数学函数:

  • mcMod, mcDiv,计算数学意义上的取模运算和除法运算(计算机实现并不正确)
  • long balRem(long a, long q),平衡的余数
  • long multOrd(long p, long m),乘法阶
  • ppsolve, ppInvert,求解方阵的方程组,求方阵的逆
  • double log2(const NTL::xdouble& x),底 2 的对数
  • void factorize(std::vector<long>& factors, long N),较小整数的因子分解
  • void pp_factorize(std::vector<long>& factors, long N),分解为素数幂
  • void phiN(long& phiN, std::vector<long>& facts, long N),欧拉函数
  • findGenerators,计算 Z m ∗ / ( p ) \mathbb Z_m^*/(p) Zm/(p) 的生成元以及它们的阶
  • FindPrimitiveRoot,本原单位根
  • long mobius(long n),莫比乌斯函数
  • NTL::ZZX Cyclotomic(long N),分圆环
  • NTL::ZZX makeIrredPoly(long p, long d),不可约多项式
  • long primroot(long N, long phiN),本原根
  • PolyRed, vecRed,取模
  • MulMod, balanced_MulMod,模乘
  • convert,一大堆不同数据类型之间的转换函数
  • long computeProd(const std::vector<long>& vec),连乘积
  • long is_in(long x, int* X, long sz),隶属问题
  • long argminmax(std::vector<T>& v),最大值、最小值
  • bool closeToOne(const NTL::xdouble& x, long p),是否落在 ( 1 − 1 / p , 1 + 1 / p ) (1-1/p,1+1/p) (11/p,1+1/p)
  • std::pair<long, long> rationalApprox(double x, long denomBound = 0),浮点数的有理数近似
  • void reverse(NTL::Vec<T>& v, long lo, long hi),就地的向量翻转
  • void rotate(NTL::Vec<T>& v, long k),就地的向量旋转
  • void killVec(std::vector<T>& vec),释放向量的内存
  • bool sameObject(const T1* p1, const T2* p2),检查两个输入是否是同一个对象
  • void ModComp(NTL::ZZX& res,const NTL::ZZX& g, const NTL::ZZX& h, const NTL::ZZX& f),多项式复合 g ( h ) ( m o d f ) g(h)\pmod f g(h)(modf)
  • long polyEvalMod(const NTL::ZZX& f, long x, long p),多项式求值 f ( x ) ( m o d p ) f(x) \pmod p f(x)(modp)
  • void interpolateMod(NTL::ZZX& poly, const NTL::vec_long& x, const NTL::vec_long& y, long p, long e = 1),拉格朗日插值
  • double Norm(const std::vector<T>& x),无穷范数
  • double Distance(const std::vector<T>& x, const std::vector<U>& y),无穷范数诱导的距离
  • bool approx_equal(const T& x, const U& y, double tolerance, double floor),近似相等
  • double NextPow2(double x),下一个二的幂次

Context.h

本模块用于记录重要的上下文信息。首先,定义了评估安全强度的辅助函数:

  • double lweEstimateSecurity(int n, double log2AlphaInv, int hwt),输入维度 n n n,噪声比率 α \alpha α,以及 s k ∈ { 0 , ± 1 } ∗ sk \in \{0,\pm1\}^* sk{0,±1} 的汉明重量,估计它的安全强度。
  • long FindM(long k, long nBits, long c, long p, long d, long s, long chosen_m, bool verbose = false),输入密文模数 Q 0 ≈ 2 n B i t s Q_0 \approx 2^{nBits} Q02nBits,KeySwitch 矩阵列数 c c c,明文空间特征 p p p,明文槽的度数 d d d 和个数 s s s,确定出参数 m m m 的大小。

定义了 struct Context::ModChainParamsstruct Context::BootStrapParamsstruct Context::SerializableContent,分别记录密文模数、自举参数、序列化(用于读写数据)

定义了 class Context,用于存储方案的关键信息,下面的其他模块依赖于此。

  • std::vector<Cmodulus> moduli,私有属性,用于存储不同的素数,这个列表只增(不减不改)
  • zMStar, alMod, slotRing,私有属性,记录代数结构 Z m ∗ \mathbb Z_m^* Zm Z [ X ] / ( Φ m ( X ) , p r ) \mathbb Z[X]/(\Phi_m(X),p^r) Z[X]/(Φm(X),pr) Z [ X ] / ( G ( X ) , p r ) \mathbb Z[X]/(G(X),p^r) Z[X]/(G(X),pr)
  • stdev = 3.2, scale = 10,私有属性,记录噪声和明文缩放因子
  • ctxtPrimes, specialPrimes,smallPrimes,私有属性,记录 pk 和 ct 的模数,记录 Key-Switch 使用的模数,记录 modulus-Switch 使用的模数
  • std::vector<IndexSet> digits,私有属性,记录 Key-Switch 中的数字分解,每个 digits[i] 是多个素数的乘积
  • ThinRecryptData rcData,私有属性,记录 “thin” 或者 “thick” 自举信息
  • Context(unsigned long m, unsigned long p, unsigned long r, const std::vector<long>& gens, const std::vector<long>& ords),构造函数,CKKS 方案的 r 是 bit precision,BGV 方案的 r 是 Hensel lifting parameter,gens, ords 是群 Z m ∗ \mathbb Z_m^* Zm 的循环结构
  • getM, getP, getPhiM, getOrdP, getNSlots, getScale, getStdev, getR, getPPowR, getrecision, getSlotRing, getsCtxtPrimes, getsDigit, getRcData,获取相关参数
  • getZMStar, getAlMod, getEA, sharedEA,获取 PAlgebra zMStarPAlgebraMod alModstd::shared_ptr<const EncryptedArray> ea 的引用
  • noiseBoundForUniform, noiseBoundForMod, noiseBoundForGaussian, noiseBoundForSmall, noiseBoundForHWt,高概率的噪声估计
  • stdDevForRecryption, boundForRecryption,自举噪声估计
  • void enableBootStrapping(const NTL::Vec<long>& mvec, bool build_cache = false, bool alsoThick = true),初始化自举数据 rcData,输入的 mvec 是参数 m m m 的唯一素分解
  • fullPrimes, allPrimes,前者获取 ctxtPrimes + specialPrimes,后者还额外获取 smallPrimes,返回值都是 IndexSet 句柄
  • ithPrime, ithModulus,获取特定位置的素数、模数
  • logOfPrime, logOfProduct, bitSizeOfQ,获取某些数值的规模
  • double securityLevel(),估计安全强度,其中 s = 3.2 ⋅ m s=3.2 \cdot \sqrt m s=3.2m α = s / q \alpha=s/q α=s/q n = ϕ ( m ) n=\phi(m) n=ϕ(m)
  • clearModChain, buildModChain, endBuildModChain,构造密文模数链

定义了 template <typename SCHEME> class ContextBuilder,用于构造 Context 对象,

  • gens_, ords_, m_, p_, r_, c_, ...,私有的数据属性,存储若干的必要参数
  • m, p, r, precision, scale, stdev, c, gens, ords, bits, skHwt, ...,公开的函数属性,用于初始化
  • mvec, thinboot, thickboot, buildCache, bootstrappable,BGV 方案的自举相关
  • Context build(),根据自身存储的信息,构造上下文对象

primeChain.h

定义了 class ModuliSizes,用于根据 modulo-size 确定 primeSets

  • typedef std::pair<double, IndexSet> Entry,存储 (size, set-of-primes) 元组
  • void init(const Context& context),初始化素数存储表
  • IndexSet getSet4Size(double low, double high, const IndexSet& fromSet, bool reverse),确定指标集 formSet 中的最大子集,使得这些素数的乘积满足区间 [low, high]

CModulus.h

文件 bluestein.hNumbTh.h 实现了 Bluestein-FFT/NTT 算法,它可以计算任意长度(不只是二的幂次)的卷积运算。渐进复杂度中的常数因子比常规 FFT/NTT 大了 3 3 3 倍。

这个算法的高级接口是 class Cmodulus,数据类型是 NTL::zz_pX(也就是 long

  • q, qinv, root, rInv, m_inv, zMStar,私有属性,记录相关参数
  • powers, powers_aux, Rb, ipowers, ipowers_aux, iRb,私有属性,用于辅助存储一些预计算数据
  • void FFT(NTL::vec_long& y, const zzX& x),正向 FFT/NTT 运算
  • void iFFT(NTL::zz_pX& x, const NTL::vec_long& y),逆向 FFT/NTT 运算

DoubleCRT.h

定义了 class DoubleCRT,构造 L L L ϕ ( m ) \phi(m) ϕ(m) 列矩阵,第 i i i 行使用 p i p_i pi 素数执行 FFT/NTT。所包含的属性:

  • const Context& context,私有属性,绑定到某个上下文,记录了 ctxtPrimesspecialPrimes 信息
  • DoubleCRT(const NTL::ZZX& poly, const Context& _context, const IndexSet& indexSet),根据上下文(记录了可用的素数 context.ithPrime(i))以及使用的素数索引 IndexSet(动态数组),将 poly 转变为 DoubleCRT 格式
  • long getOneRow(NTL::zz_pX& row, long idx),获取 DoubleCRT 的某一行多项式(系数表示)
  • void toPoly(NTL::ZZX& p, const IndexSet& s, bool positive = false),将指定行的数据合成为多项式
  • void addPrimes(const IndexSet& s1, NTL::ZZX* poly_p = 0),将 DoubleCRT 扩展一些行(先将现有的数据 IFFT,然后对新添的素数做 FFT)
  • void removePrimes(const IndexSet& s1),将 DoubleCRT 删除一些行(简单删除,效果是简单取模)
  • void setPrimes(const IndexSet& s1),从当前 CRT 基转换到 IndexSet 指定的基
  • DoubleCRT& SetZero(), DoubleCRT& SetOne(),设置数值
  • DoubleCRT& Negate(), +=, -=, *=, /=, ==, !=,基本运算符

hypercube.h

定义了 class CubeSignature,存储高阶立方(明文槽)的维度信息。

  • dims, prods,私有属性,前者存储各个维度的大小,后者存储 slice 的规模 p r o d s [ d ] = ∏ j = d n − 1 d i m s [ j ] prods[d] = \prod_{j=d}^{n-1} dims[j] prods[d]=j=dn1dims[j](固定前 d 个坐标,遍历后 n-d 个坐标;特别地,仅固定第 0 个坐标称为 col
  • getNumDims, getSize, getDim, getProd, numSlices, sliceSize, numCols,获取 dim, slice, col 的信息
  • long getCoord(long i, long d),计算索引 i 在第 d 维上的坐标
  • void getAllCoords(VecType& v, long i),获取索引 i 的高阶立方上的坐标 v
  • long assembleCoords(VecType& v),将坐标 v 重构为索引 i
  • long addCoord(long i, long d, long offset),确定索引 i 在第 d 维上的坐标偏移 offset 之后的新索引 i'
  • bool incrementCoords(VecType& v),根据坐标 v,确定它的索引 i 的下一个索引

定义了 template <typename T> class HyperCube,管理高阶立方中的数据对象。

  • NTL::Vec<T> data,存储数据(高阶立方被存储为单个向量)
  • ==, !=,判断两个立方的形状和数据是否完全相同
  • getSig, getData, getDim, getNumDims, getProd, getCoord, numSlices, sliceSize, numCols,获取相关的维度、规模信息
  • at, [],获取索引 i 的数据引用
  • rotate1D(i, k), shift1D(i, k),将维度 i 右旋/右移 k

定义了 class ConstCubeSlice, class CubeSlice,用于管理某个 slice

另外,getHyperColumn, setHyperColumn,获取/设置高阶立方的某个 col

PAlgebra.h

定义了 class PAlgebra,用于支持 Z m ∗ ≅ ( p ) × ( g 1 , g 2 , ⋯   ) × ( f 1 , f 2 , ⋯   ) \mathbb Z_m^* \cong (p) \times (g_1,g_2,\cdots) \times (f_1,f_2,\cdots) Zm(p)×(g1,g2,)×(f1,f2,),它同构于分圆整数环 A : = Z [ X ] / ( Φ m ( X ) ) \mathbb A:=\mathbb Z[X]/(\Phi_m(X)) A:=Z[X]/(Φm(X)) 的 Galois 群。此结构完全由 m , p m,p m,p 决定,其中 p p p 是满足 p ∤ m p \nmid m pm 的素数。群 ( g 1 , g 2 , ⋯   ) (g_1,g_2,\cdots) (g1,g2,) 包含所有的 ”在 Z m ∗ \mathbb Z_m^* Zm Z m ∗ / ( p , g 1 , ⋯   , g i − 1 ) \mathbb Z_m^*/(p,g_1,\cdots,g_{i-1}) Zm/(p,g1,,gi1) 中拥有相同阶“ 的那些元素,群 ( f 1 , f 2 , ⋯   ) (f_1,f_2,\cdots) (f1,f2,) 生成商群 Z m ∗ / ( p , g 1 , g 2 , ⋯   ) \mathbb Z_m^*/(p,g_1,g_2,\cdots) Zm/(p,g1,g2,)

查找表 T ⊆ Z m ∗ T \subseteq \mathbb Z_m^* TZm 是商群 Z m ∗ / ( p ) \mathbb Z_m^*/(p) Zm/(p) 的全部陪集的代表,
T : = { ∏ i g i e i ⋅ ∏ j h j e j ∣ e i ∈ [ o r d ( g i ) ] , e j ∈ [ o r d ( h j ) ] } T:=\left\{\prod_i g_i^{e_i} \cdot \prod_j h_j^{e_j} \Big| e_i \in [ord(g_i)], e_j \in [ord(h_j)]\right\} T:={igieijhjej ei[ord(gi)],ej[ord(hj)]}
假设 ∣ T ∣ = l |T|=l T=l,我们令 d = ϕ ( m ) / l d=\phi(m)/l d=ϕ(m)/l,那么在 ( m o d p r ) \pmod{p^r} (modpr) 意义下,有如下的分圆多项式分解:
Φ m ( X ) = ∏ t ∈ T F t ( X ) \Phi_m(X) = \prod_{t \in T} F_t(X) Φm(X)=tTFt(X)
易知 1 ∈ T 1 \in T 1T,对于 r = 1 r=1 r=1,首先确定任意的不可约因子设为 F 1 ( X ) F_1(X) F1(X),然后计算其他的因子 F t ( X ) = gcd ⁡ ( F 1 ( X t ) , Φ m ( X ) ) F_t(X)=\gcd(F_1(X^t),\Phi_m(X)) Ft(X)=gcd(F1(Xt),Φm(X)),这些 l l l 个不可约因子次数都为 d d d。固定多项式环 R : = Z p [ X ] / ( F 1 ( X ) ) R:=\mathbb Z_p[X]/(F_1(X)) R:=Zp[X]/(F1(X)),假如 ρ \rho ρ F 1 F_1 F1 的根,那么 ρ 1 / t \rho^{1/t} ρ1/t 的极小多项式是 F t ( X ) F_t(X) Ft(X)。对于 r > 1 r>1 r>1,需要使用 Hensel Lifting 给出 Φ m ( X ) \Phi_m(X) Φm(X) 的分解,各个 F t F_t Ft 之间也有类似的关系。因此,这些明文槽都是同构的。解码过程为:
a ∈ Z p r [ X ] / ( Φ m ( X ) ) ↦ { a ( ζ t ) ∈ Z p r [ X ] / ( F t ) } t ∈ T a \in \mathbb Z_{p^r}[X]/(\Phi_m(X)) \mapsto \{a(\zeta^t) \in \mathbb Z_{p^r}[X]/(F_t)\}_{t \in T} aZpr[X]/(Φm(X)){a(ζt)Zpr[X]/(Ft)}tT
其中 ζ \zeta ζ Z p r [ X ] / ( F 1 ) \mathbb Z_{p^r}[X]/(F_1) Zpr[X]/(F1) 中的某固定 m m m-th 本原单位根。

class PAlgebra 的属性:

  • m, p, phiM, ordP, nfactors, radm, normBnd, polyNormBnd,私有属性,管理相关参数
  • std::vector<long> gens,私有属性,管理 Z m ∗ \mathbb Z_m^* Zm 的生成元
  • NTL::Vec<bool> native,私有属性,native[i]=true 指示 gens[i] 落在子群 ( g 1 , g 2 , ⋯   ) (g_1,g_2,\cdots) (g1,g2,)
  • NTL::Vec<long> frob_perturb,私有属性,frob_perturb[i]=j 指示 gens[i] 的乘法阶为 p j p^j pj
  • CubeSignature cube,私有属性,管理 Z m ∗ / ( p ) \mathbb Z_m^*/(p) Zm/(p) 的高阶立方的结构
  • std::vector<long> T, Tidx,私有属性,前者 T[i]=t 记录了各个代表元 t ∈ Z m ∗ / ( p ) t \in \mathbb Z_m^*/(p) tZm/(p),后者 Tidx[t]=i 是反过来的
  • std::vector<long> zmsIdx, zmsRep,私有属性,前者 zmsIdx[t]=i 记录了 t ∈ Z m ∗ t \in \mathbb Z_m^* tZm 的次序 i,后者是反过来的
  • long getPhiM(),返回 ϕ ( m ) \phi(m) ϕ(m)(多项式 Φ m ( X ) \Phi_m(X) Φm(X) 的次数)
  • long getRadM(),返回 R a d ( m ) Rad(m) Rad(m)(不同素因子的乘积)
  • const NTL::ZZX& getPhimX(),返回 Φ m ( X ) \Phi_m(X) Φm(X)
  • long getNSlots(),返回明文槽的数量 l l l
  • double get_cM(),返回环常数 c M c_M cM(随机元素在不同 bases 下无穷范数的比值,仅用于自举)
  • long numOfGens(),返回 Z m ∗ / ( p ) \mathbb Z_m^*/(p) Zm/(p) 的生成元个数
  • long ZmStarGen(long i),返回 Z m ∗ / ( p ) \mathbb Z_m^*/(p) Zm/(p) 的生成元 gens[i]
  • long OrderOf(long i),返回 gens[i] 的乘法阶(高阶立方 cubei 维度的规模)
  • long frobeniusPow(long j),返回 Frobenius 映射的指数 p j ( m o d m ) p^j \pmod m pj(modm)
  • long ith_rep(long i),返回第 i i i 个明文槽的代表 T[i]
  • long indexInZmstar(long t),返回元素 t ∈ Z m ∗ t \in \mathbb Z_m^* tZm 的索引 zmsIdx[t]
  • long coordinate(long i, long k),返回索引 k 在维度 i 上的坐标

定义了 class MappingData,用于管理 encoding/decoding slots 的映射信息

  • G, degG,私有属性,域扩张多项式 G ( X ) G(X) G(X),它是 Φ m ( X ) ( m o d p r ) \Phi_m(X) \pmod{p^r} Φm(X)(modpr) 的任意不可约因子
  • maps, matrix_maps, rmaps,私有属性,存储了映射

定义了 class PAlgebraMod,用于支持 Z p r [ X ] \mathbb Z_{p^r}[X] Zpr[X] 上的 encode/decode slots 过程。各个明文槽的结构为 Z p r [ X ] / ( F t ( X ) ) ≅ Z p r [ X ] / ( F 1 ( X ) ) \mathbb Z_{p^r}[X]/(F_t(X)) \cong \mathbb Z_{p^r}[X]/(F_1(X)) Zpr[X]/(Ft(X))Zpr[X]/(F1(X)),简记 R [ X ] : = Z p r [ X ] R[X]:=\mathbb Z_{p^r}[X] R[X]:=Zpr[X]

首先定义了 template <typename type> class PAlgebraModDerived : public PAlgebraModBase 实例化,包含的属性有:

  • const PAlgebra& zMStar,私有属性,管理 Z m ∗ \mathbb Z_m^* Zm 的高阶立方结构
  • r, pPowR, PhimXMod,私有属性,管理相关的参数
  • const vec_RX& getFactors(),返回 Φ m ( X ) ( m o d p r ) \Phi_m(X) \pmod{p^r} Φm(X)(modpr) 的分解 F t ∈ R [ X ] F_t \in R[X] FtR[X]
  • const vec_RX& getCrtCoeffs(),返回 CRT 基 ( ∏ j ≠ i F j ) − 1 ( m o d F i ) (\prod_{j \neq i}F_j)^{-1} \pmod{F_i} (j=iFj)1(modFi)
  • CRT_decompose, CRT_reconstruct,计算多项式 RX H 的 CRT 分解 vector<RX> crt
  • void mapToSlots(MappingData<type>& mappingData, const RX& G),根据 G ( X ) G(X) G(X) 计算出到 slots 的映射
  • void embedInSlots(RX& H, const std::vector<RX>& alphas, const MappingData<type>& mappingData),将 [ α 0 , ⋯   , α l − 1 ] [\alpha_0,\cdots,\alpha_{l-1}] [α0,,αl1] 编码到 H ∈ R [ X ] / ( Φ m ( X ) ) H \in R[X]/(\Phi_m(X)) HR[X]/(Φm(X)) 的 slots 上

class PAlgebraMod 就是某个 PAlgebraModBase 对象实例的指针,

  • ClonedPtr<PAlgebraModBase> rep,私有属性
  • explicit PAlgebraMod(const PAlgebra& zMStar, long r),根据 A p \mathbb A_p Ap r r r 构造 A p r \mathbb A_{p^r} Apr
  • const PAlgebra& getZMStar(),返回底层的 PAlgebra 结构(在 rep 里存储)
  • const std::vector<NTL::ZZX>& getFactorsOverZZ(),返回 Φ m ( X ) ( m o d p r ) \Phi_m(X) \pmod{p^r} Φm(X)(modpr) 的分解(在 rep 里存储)

permutatios.h

使用 typedef NTL::Vec<long> Permut 描述简单置换 p [ i ] = π i p[i] = \pi_i p[i]=πi

  • void applyPermToVec(std::vector<T>& out, const std::vector<T>& in, const Permut& p1),执行一个置换,输出 o u t [ i ] = i n [ p 1 [ i ] ] out[i] = in[p_1[i]] out[i]=in[p1[i]]
  • void applyPermsToVec(std::vector<T>& out, const std::vector<T>& in, const Permut& p2, const Permut& p1),连续执行两个置换,输出 o u t [ i ] = i n [ p 2 [ p 1 [ i ] ] ] out[i] = in[p_2[p_1[i]]] out[i]=in[p2[p1[i]]]

定义了 class ColPerm : public HyperCube<long>,用于置换高阶立方的某一列

定义了 class GeneralBenesNetwork,使用 Benes Network 实现任意的置换(自同构仅提供简单的移位置换)

定义了 template <typename T> class FullBinaryTree,代数结构 Z m ∗ / ( p ) \mathbb Z_m^*/(p) Zm/(p) 的各个生成元,都需要一棵完全二叉树,用于高阶立方各个维度的任意置换

定义了 class PermNetwork,这是一个 “背靠背” 蝴蝶网络,

  • NTL::Vec<PermNetLayer> layers,私有属性,记录了置换网络的各层信息
  • PermNetwork(const Permut& pi, const GeneratorTrees& trees),根据映射 pi 构造置换网络
  • void applyToCtxt(Ctxt& c, const EncryptedArray& ea),密文槽的同态置换

定义了 class PermIndepPrecompclass PermPrecomp,前者是 permutation-independent 预计算,后者是 permutation-dependent 预计算。

PolyModRing.h

定义了 struct PolyModRing,它是明文槽的环结构,都同构于 Z [ X ] / ( G ( X ) , p r ) \mathbb Z[X]/(G(X), p^r) Z[X]/(G(X),pr),其中 G = F t G=F_t G=Ft 是分圆多项式 Φ m ( X ) ( m o d p r ) \Phi_m(X) \pmod{p^r} Φm(X)(modpr) 的任意不可约因子。属性如下:

  • PolyModRing(long p, long r, const NTL::ZZX& G),根据参数构造明文槽的环结构
  • friend std::ostream& operator<<(std::ostream& os, const PolyModRing& ring),打印环结构的参数

PolyMod.h

定义了 class PolyMod,用于存储 Z p r [ X ] / ( G ( X ) ) \mathbb Z_{p^r}[X]/(G(X)) Zpr[X]/(G(X)) 中的多项式。

  • PolyMod(const std::vector<long>& input, const std::shared_ptr<PolyModRing>& ringDescriptor),根据 PolyModRing 将系数表示(input[i]表示 x i x^i xi 的系数)转化为环元素
  • ==, !=, -, *, +, -, *=, +=, -=,基本运算
  • friend std::ostream& operator<<(std::ostream& os, const PolyMod& poly),打印多项式

Sample.h

定义了随机采样的一些函数,

  • sampleSmall,随机的三元分布
  • sampleHWt,给定汉明重量的三元分布
  • sampleGaussian,高斯分布
  • sampleUniform,均匀分布

Crypto Layer

scheme.h

定义了 struct CKKSstruct BGV,用于确定方案的底层代数结构。

  • CKKS 方案,明文槽结构 std::complex<double>,也就是 C \mathbb C C 的浮点数近似
  • BGV 方案,明文槽结构 PolyMod,形如 Z p r [ X ] / ( G ( X ) ) \mathbb Z_{p^r}[X]/(G(X)) Zpr[X]/(G(X)),其中 G G G Φ m ( X ) \Phi_m(X) Φm(X) 的不可约因子

Ptxt.h

定义了明文空间的一些功能,

  • std::vector<typename Scheme::SlotType> convertDataToSlotVector(const std::vector<From>& data, const Context& context)
    • BGV方案,将 vector<From> 转换为 vector<PolyMod>,这里的 From 可以是 NTL::ZZX
    • CKKS 方案,将 vector<From> 转换为 vector<std::complex<double>>,这里的 From 可以是 double

定义了 template <typename Scheme> class Ptxt

  • explicit Ptxt(const Context& context),根据上下文初始化
  • Ptxt(const Context& context, const SlotType& value),将明文槽都设置为 value
  • template <typename T> Ptxt(const Context& context, const std::vector<T>& data),将向量 data 转化到明文槽中
  • size_t size(),返回明文槽的数量 size
  • const Context& getContext(),返回自身的上下文
  • void setData(const SlotType& value),设置明文槽的值
  • void decodeSetData(const NTL::ZZX& data),使用多项式 ZZX 解码后的 slots 设置明文,BGV 专用
  • void clear(), Ptxt<Scheme>& random(),清理明文、随机明文
  • const std::vector<SlotType>& getSlotRepr(),获取明文的 slots 表示
  • NTL::ZZX getPolyRepr(),获取明文的 coeff 表示
  • void encode(EncodedPtxt& eptxt, double mag = -1, OptLong prec = OptLong()),将自身(solts 形式)编码为 EncodedPtxt(poly 形式)
  • ==, !=, *, +, -, *=, +=, -=, negate,基本运算
  • Ptxt<Scheme>& addConstant(const Scalar& scalar),全部明文槽都加常数,BGV 专用
  • Ptxt<Scheme>& addConstantCKKS(const Scalar& scalar),全部明文槽都加常数,CKKS 专用
  • multiplyBy, multiplyBy2, square, cube, power,乘法、幂次
  • Ptxt<Scheme>& rotate(long amount),循环右移,槽 i 移动到 i+amount mod size
  • Ptxt<Scheme>& rotate1D(long dim, long amount),高阶立方体 dim 维度上的循环右移,是由 Z m ∗ \mathbb Z_m^* Zm 的循环群结构 PAlgebra& zMStar = context->getZMStar() 所诱导的
  • Ptxt<Scheme>& shift(long amount),零填充右移
  • Ptxt<Scheme>& shift1D(long dim, long amount),高阶立方体 dim 维度上的零填充右移
  • Ptxt<Scheme>& automorph(long k),自同构映射 a ( X ) ↦ a ( X k ) ( m o d Φ m ( X ) ) a(X) \mapsto a(X^k) \pmod{\Phi_m(X)} a(X)a(Xk)(modΦm(X)),其中 k ∈ Z m ∗ k \in \mathbb Z_m^* kZm
  • Ptxt<Scheme>& frobeniusAutomorph(long j),Frobenius 自同构 a ( X ) ↦ a ( X p j ) ( m o d Φ m ( X ) ) a(X) \mapsto a(X^{p^j}) \pmod{\Phi_m(X)} a(X)a(Xpj)(modΦm(X)),BGV 专用
  • Ptxt<Scheme>& replicate(long pos),第 pos 个明文槽的广播复制
  • complexConj, real, imag,复数变换,CKKS 专用
  • runningSums, totalSums,明文槽加和,前者是前缀槽的和,后者是全部槽的和
  • incrementalProduct, totalProduct,明文槽乘积,前者是前缀槽的积,后者是全部槽的积

EncodedPtxt.h

定义了 class EncodedPtxt_BGV

  • EncodedPtxt_BGV(const zzX& poly_, long ptxtSpace_, const Context& context_),构造函数
  • getPoly, getPtxtSpace, getContext,查看存储的信息

定义了 class EncodedPtxt_CKKS

  • EncodedPtxt_CKKS(const zzX& poly_, double mag_, double scale_, double err_, const Context& context_),构造函数
  • getPoly, getMag, getScale, getErr, getContext,查看存储的信息

定义了 class EncodedPtxt,它要么存储 EncodedPtxt_BGV 要么存储 EncodedPtxt_CKKS,存储结构是 zzX poly

  • eptxt.isBGV(), eptxt.isCKKS(),判断自己是哪个方案
  • eptxt.getBGV(), eptxt.getCKKS(),生成只读的 EncodedPtxt_BGVEncodedPtxt_CKKS 对象引用
  • eptxt.resetBGV(), eptxt.resetCKKS(),重置 EncodedPtxt_BGVEncodedPtxt_CKKS 对象

定义了 FatEncodedPtxt_BGVclass FatEncodedPtxt_CKKSclass FatEncodedPtxt,接口是一样的,但是存储结构为 DoubleCRT dcrt

Ctxt.h

定义了 class SKHandle,用于描述满足形式 s r ( X t ) s^r(X^t) sr(Xt) 的私钥元素(同态乘法导致 s r ( X ) s^r(X) sr(X),同态自同构导致 s ( X t ) s(X^t) s(Xt)),属性 powerOfS, powerOfX, secretKeyID(是私钥句柄,用于描述解密时 CtxtPart 应当乘以哪一个私钥)记录了信息 ( r , t , i ) (r,t,i) (r,t,i),用于辅助解密。句柄之间定义了等性检测和乘法运算。

定义了 class CtxtPart : public DoubleCRT,用于存储密文中的单个多项式,包含一个 SKHandle 对象,并继承了 DoubleCRT 的属性(以 DCRT 格式存储和计算)。密文形如 ( c 0 , c 1 , ⋯   , c k ) (c_0,c_1,\cdots,c_k) (c0,c1,,ck),私钥形如 s i ( X t ) s_i(X^t) si(Xt),解密公式为 ∑ r c r ( X ) ⋅ s r ( X t ) \sum_r c_r(X) \cdot s^r(X^t) rcr(X)sr(Xt),因此各个 CtxtPart 记录了私钥句柄 ( r , t , i ) (r,t,i) (r,t,i)

定义了 class Ctxt,使用 std::vector<CtxtPart> parts 对象来存储密文 c[i] = part[i]。BGV 密文中加密的消息是 [ q ⋅ m ] p r [q \cdot m]_{p^r} [qm]pr,在模切换过程中保持因子 [ q ] p r [q]_{p^r} [q]pr 对应当前的密文模数。密文同态加法时,相同句柄的相加,不同句柄的简单存储;密文同态乘法时,计算 part, part' 的张量积,它们的句柄两两相乘。

  • context, pubKey,私有属性,密文相关参数的指针
  • parts, primeSet, ptxtSpace, noiseBound,私有属性,存储密文各个分量、用到的素数、明文模数、平均噪声估计
  • intFactor, ratFactor, ptxtMag,私有属性,前者用于 BGV 纠错,后两者用于 CKKS 纠错(尾数部分,指数部分)
  • tensorProduct, subPart, addPart, keySwitchPart, keySwitchDigits,私有属性,用于同态运算
  • ==, !=,检查两个 Ctxt 对象的 size, primeSet, intFactor, noiseBound 是否相同
  • negate, +=, -=, *=,基本的同态运算。支持不同密文模数的加法,结果是素数集的并集;支持不同密文模数的乘法,结果是素数集的交集。这里都是 “high-level” 版本,计算结果自动执行模切换和重线性化。
  • void multLowLvl(const Ctxt& other, bool destructive = false); 自动执行模切换,但是不执行重线性化。
  • addConstant, multByConstant,前者首先将输入的常数缩放 [ q ] p r [q]_{p^r} [q]pr 然后再加到 c t ( s i ) ct(s_i) ct(si) 的常数项,后者就是简单将 c t ( s ) ct(s) ct(s) 乘以输入的常数。对于频繁使用的常数,可以将它用 ea.encode 预先编码为 EncodedPtxt,然后使用 FatEncodedPtxt(eptxt, context.fullPrimes()) 获取它的 DoubleCRT 表示。
  • xorConstant, nxorConstant,根据公式 a ⊕ b = a + b − 2 a b a \oplus b = a+b-2ab ab=a+b2ab ( a ⊕ b ) ‾ = 1 − a − b + 2 a b \overline{(a \oplus b)}=1-a-b+2ab (ab)=1ab+2ab,计算任意明文模数下的异或运算(需要同态乘法)
  • void automorph(long k),自同构映射 F ( X ) → F ( X k ) F(X) \to F(X^k) F(X)F(Xk),其中 gcd ⁡ ( k , m ) = 1 \gcd(k,m)=1 gcd(k,m)=1,这是 “raw” 版本,各个 part[i] 句柄的 powerOfX 乘以 k
  • void smartAutomorph(long k),它根据 context 中提供的 KSK 将自同构 X → X k X \to X^k XXk 拆分为 X → X k i , i = 1 , ⋯   , t X \to X^{k_i},i=1,\cdots,t XXki,i=1,,t,依次执行各个自同构,紧接着自动执行对应的 KS 过程。在生成 KSK 的同时确定了一个表格 keySwitchMap[i][k],记录了各个 k 对应的自同构序列。
  • void frobeniusAutomorph(long j),也就是 smartAutomorph(p^j mod m)
  • divideByP, multByP,简单作用到密文上,使得明文模数分别变为 p r − 1 , r > 1 p^{r-1},r>1 pr1,r>1 p r + 1 , r ≥ 1 p^{r+1},r\ge1 pr+1,r1
  • multiplyBy, multiplyBy2, square, cube, power,高等的同态乘法,它们自动执行模切换和重线性化运算,甚至自动选取计算顺序。
  • void evalPoly(const NTL::ZZX& poly),执行同态多项式求值
  • reducePtxtSpace, hackPtxtSpace,模切换过程,后者在明文高位引入噪声
  • void blindCtxt(const NTL::ZZX& poly),盲化 BGV 密文,加上常数 poly 的高噪声密文
  • NTL::xdouble modSwitchAddedNoiseBound(),估计模切换带来的额外噪声
  • modUpToSet, modDownToSet, bingToSet,模切换过程,前两者添加/删除一些素数(同时缩放对应的倍率,保持明文的因子 [ q ] p r [q]_{p^r} [q]pr),后者先 UpDown
  • void Ctxt::reLinearize(long keyID),重线性化过程,keyID 确定要切换到的私钥 ( 1 , s i ) (1,s_i) (1,si),采取了 [BV11] 和 [GHS12] 的混合方案,首先 ScaleDown 移除 SpecialPrimes,然后 KS 过程中 ScaleUp 重新引入它们,最终的输出密文模数包含了这些素数(副作用)
  • void dropSmallAndSpecialPrimes(),移除 Key-Switch 过程的副作用(密文模数放大了 SpecialPrimes),同时会自动添加一些 ctxtPrimes 使得模切换的额外噪声可忽略
  • totalNoiseBound, errorBound,前者估计相位中的噪声(CKKS 要加上 ptxtMag * ratFactor 精度损失),后者估计明文中的噪声(BGV 的是零)。同态运算过程中,自动执行启发式的噪声估计,存储在 noiseBound 内。
  • capacity, bitcapacity,两者返回的都是 log ⁡ 2 ( Q / B ) \log_2(Q/B) log2(Q/B),标志着同态运算的能力,其中 B = totalNoiseBound() 是噪声界
  • bool isCorrect(),判断是否能够正确解密
  • getContext, getPubKey, getPrimeSet, getPtxtSpace, getNoiseBound, getRatFactor, getPtxtMag, getKeyID,获取本密文的相关信息
  • addedNoiseForCKKSDecryption,对 CKKS 解密结果添加噪声,防止 Approximate FHE IND-CPA+ 攻击

定义了一些自由函数,

  • totalProduct, incrementalProduct, innerProduct,特殊同态乘法的加速实现(二叉树、统一重线性化)
  • conjugate, extractRealPart, extractImPart,CKKS 专用,利用自同构 ctxt.frobeniusAutomorph(1)(同态复共轭)同态提取实部/虚部
  • void extractDigits(std::vector<Ctxt>& digits, const Ctxt& c, long r = 0),BGV 专用,提取明文槽 Z p r [ X ] / ( G ) \mathbb Z_{p^r}[X]/(G) Zpr[X]/(G) 的各个 mod- p p p deigits,其中 digit[j] 的明文模数分别是 p r − j p^{r-j} prj,但是这些密文的 Level 相同
  • extractBits, extendExtractDigits,其他的数字分解
  • void CheckCtxt(const Ctxt& c, const char* label),打印密文的错误信息

Key.h

定义了 class PubKey,管理公钥数据以及相关接口,

  • Ctxt pubEncrKey,私有属性,公钥就是零的密文 p k = R L W E s ( 0 ) pk = RLWE_s(0) pk=RLWEs(0)
  • std::vector<KeySwitch> keySwitching,私有属性,记录了多个秘钥切换矩阵 W [ s ′ → s ] W[s' \to s] W[ss],其中 s ′ ∈ { s i r ( X t ) } s' \in \{s_i^r(X^t)\} s{sir(Xt)},以及 s ∈ { s j ( X ) } s \in \{s_j(X)\} s{sj(X)}
  • std::vector<std::vector<long>> keySwitchMap,私有属性,这是个指针数组,keySwitchMap[i][e] = j 记录了对 s i ( X e ) s_i(X^e) si(Xe) 重线性化时应当使用 keySwitching[j]
  • Ctxt recryptEkey,私有属性,存储了自举秘钥
  • void Encrypt(Ctxt& ctxt, const EncodedPtxt& eptxt),公钥加密
  • void reCrypt(Ctxt& ctxt), void thinReCrypt(Ctxt& ctxt),自举程序,后者要求 slots 内加密的是数值而非多项式
  • void hackPtxtSpace(long p2r),强行提升明文模数,在 BGV 中会引入高位噪声

定义了 class SecKey : public PubKey,管理私钥数据以及相关接口,

  • std::vector<DoubleCRT> sKeys,私有属性,存储了若干的私钥 s i s_i si,它们被 CtxtPart 句柄中的 secretKeyID 索引,用于 Level FHE(移除循环安全假设)
  • GenSecKey, GenKeySWmatrix, getRecryptKey,生成各种秘钥 SK, KSK, BSK
  • void Decrypt(NTL::ZZX& plaintxt, const Ctxt& ciphertxt),解密
  • long skEncrypt(Ctxt& ctxt, const zzX& ptxt, long ptxtSpace, long skIdx),对称加密

此外,double RLWE(DoubleCRT& c0, DoubleCRT& c1, const DoubleCRT& s, long p, NTL::ZZ* prgSeed = nullptr),产生随机的 RLWE 样本,返回的 double 是典范嵌入的无穷范数。

KeySwitching.h

有两种 KS 程序,其一是 [BV11] 的数字分解技术,其二是 [GHS12] 的模数扩展技术。这里的实现是 Hybrid 技巧。

定义了 class KeySwitch,它存储形如 W [ s ′ → s ] = ( a ⃗ , b ⃗ ) T ∈ R Q 2 × t W[s' \to s]=(\vec a, \vec b)^T \in R_Q^{2 \times t} W[ss]=(a ,b )TRQ2×t 的 KSK 矩阵,其中 Q Q Q 是全部的 ctxtPrimesspecialPrimes 的乘积,而 t t t 是这个模数的数字分解(每个 digit 是若干个素数的乘积,规模 D i D_i Di),形如 b i : = [ ( ∏ j < i D i ) ⋅ s ′ + p r e i − a i s ] Q b_i := [(\prod_{j<i}D_i) \cdot s' + p^re_i - a_is]_Q bi:=[(j<iDi)s+preiais]Q,这里的 ∏ j < i D i \prod_{j<i}D_i j<iDi 就是 Powerof2 的替代品。

  • SKHandle fromKeylong toKeyID,分别记录了 s ′ s' s s s s 的句柄/索引,形如 ( r , t , i ) (r,t,i) (r,t,i) j j j
  • NTL::ZZ prgSeedstd::vector<DoubleCRT> b,分别记录了 a ⃗ \vec a a (PRG seed)和 b ⃗ \vec b b

SecKey 内构造添加关于 KeySwitch 的自由函数,每一个私钥 s i s_i si 都携带一张有向图 G i G_i Gi,它由 keySwitchMap 指示 KSK 的路径 s i ( X e ) → s i ( X 1 ) s_i(X^e) \to s_i(X^1) si(Xe)si(X1),用于组合少量的 KS 过程获得任意的 KS 过程。

  • void addAllMatrices(SecKey& sKey, long keyID = 0),生成所有映射 s i ( X e ) ↦ s i ( X ) , ∀ e ∈ Z m ∗ s_i(X^e) \mapsto s_i(X), \forall e \in \mathbb Z_m^* si(Xe)si(X),eZm 的 KSK 矩阵,但是规模太大了(本身 m m m 就是上万的规模)
  • void addFewMatrices(SecKey& sKey, long keyID = 0),生成少量映射的 KSK 矩阵,确保 s i ( X e ) ↦ s i ( X ) , ∀ e ∈ Z m ∗ s_i(X^e) \mapsto s_i(X), \forall e \in \mathbb Z_m^* si(Xe)si(X),eZm 都可以两步以内被线性化(就是路径 e → 1 e \to 1 e1 长度至多为 2 2 2),这会导致每个 KS 过程被分解为若干步骤
  • void add1DMatrices(SecKey& sKey, long keyID = 0),生成全部形如 s i ( X g ± e ) ↦ s i ( X ) s_i(X^{g^{\large{\pm e}}}) \mapsto s_i(X) si(Xg±e)si(X) 映射的 KSK 矩阵(用于 rotate1D, shift1D,进而可以组合出任意的 automorph),其中 Z m ∗ / ( p ) = ( g ) \mathbb Z_m^*/(p) = (g) Zm/(p)=(g) e < o r d ( g ) e<ord(g) e<ord(g)。类似的,也有 addSome1DMatrices 版本,它生成上述 KSK 的某个子集,将每个 s i ( X g ± e ) ↦ s i ( X ) s_i(X^{g^{\large{\pm e}}}) \mapsto s_i(X) si(Xg±e)si(X) 分解为至多两步(因此也支持全部的 automorph
  • void addFrbMatrices(SecKey& sKey, long keyID = 0),生成全部形如 s i ( X p e ) ↦ s i ( X ) s_i(X^{p^e}) \mapsto s_i(X) si(Xpe)si(X) 映射的 KSK 矩阵(用于 frobeniusAutomorph
  • void addMatrices4Network(SecKey& sKey, const PermNetwork& net, long keyID = 0),生成置换网络 net 所需的那些 KSK 矩阵

recryption.h

对于 BGV 方案,存在 [HS15], [CH18] 两种自举算法。前者是通用的,后者专用于模数是二的幂次。HElib 给出了两种自举,“thick” 和 “thin”,前者是通用的自举程序(速度:数分钟级别),后者专用于明文限制在明文槽的基域/基环(速度:数十秒级别)

定义了 class RecryptData,用于存储自举相关的数据

  • NTL::Vec<long> mvec,参数 m m m 的素分解
  • e, ePrime, skHwt,明文空间、私钥重量
  • alMod, ea,明文槽的结构和编码解码接口
  • init, setAE,配置自举数据

定义了 class ThinRecryptData : public RecryptData,专用于 “thin” bootstrapping 的自举数据。

recryption.cpp 中定义了一些没有在 recryption.h 内声明的自由函数,可能包含在其他的头文件里,

  • extractDigitsPackedextractDigitsThin,同态数字提取
  • void PubKey::reCrypt(Ctxt& ctxt)void PubKey::thinReCrypt(Ctxt& ctxt),单个密文的自举程序
  • void packedRecrypt(const CtPtrs& cPtrs, const std::vector<zzX>& unpackConsts, const EncryptedArray& ea),利用 repack, unpackCtPtrs 中的每 deg ⁡ d \deg d degd 个密文打包在一起,批量自举

multicore.h

用于多线程的加锁和同步,

  • std::atomic_long, std::atomic_ulong,原子的整数类型
  • std::mutex, std::lock_guard<std::mutex>,资源锁

似乎它仅在 bootstrapping 中实现了多线程?

Data-Movement Layer

intraSlot.h

定义了一些关于 G F ( p d ) GF(p^d) GF(pd) 上明文槽的 Packing/Unpacking 功能,

  • void buildUnpackSlotEncoding(std::vector<zzX>& unpackSlotEncoding, const EncryptedArray& ea),预计算解包相关的信息
  • long repack(const CtPtrs& packed, const CtPtrs& unpacked, const EncryptedArray& ea),打包函数
  • long unpack(const CtPtrs& unpacked, const CtPtrs& packed, const EncryptedArray& ea, const std::vector<zzX>& unpackSlotEncoding),解包函数

EncryptedArray.h

定义了 class EncryptedArrayBase,这是 virtual 的类,用于明文槽的数据移动

  • getContext, getPAlgebra, getDegree, getP2R,获取相关参数
  • rotate, shift, rotate1D, shift1D,右旋、右移(有两种明文槽的 array view,其一是线性数组,其二是高阶立方,后者关于 Z m ∗ / ( p ) \mathbb Z_m^*/(p) Zm/(p) 的循环群结构)
  • encode, decode,数组和多项式之间的转换
  • decrypt, rawDecrypt, decryptComplex, rawDecryptComplex, rawDecryptReal, decryptReal,解密函数
  • void buildLinPolyCoeffs(std::vector<NTL::ZZX>& C, const std::vector<NTL::ZZX>& L),根据线性映射 L 构造线性多项式列表 C,两者都是公开的多项式
    • 输入向量 L ∈ ( Z p r [ X ] ) deg ⁡ G L \in (\mathbb Z_p^r[X])^{\deg G} L(Zpr[X])degG,它描述了 Z p r [ X ] / ( G ( X ) ) \mathbb Z_{p^r}[X]/(G(X)) Zpr[X]/(G(X)) 中的某线性映射,满足 M : X j   m o d   G ↦ L [ j ]   m o d   G ,    j = 0 , 1 , ⋯   , deg ⁡ G − 1 M: X^j \bmod G \mapsto L[j] \bmod G,\,\, j=0,1,\cdots,\deg G-1 M:XjmodGL[j]modG,j=0,1,,degG1,也就是 L 描述了 M 对于标准 Power Basis 的作用
    • 输出向量 C ∈ ( Z p r [ X ] ) deg ⁡ G C \in (\mathbb Z_p^r[X])^{\deg G} C(Zpr[X])degG,其中的每一个多项式都是线性的,用于计算 M : h ( X )   m o d   G ↦ ∑ j = 0 deg ⁡ G − 1 C [ j ] ⋅ h ( X p j )   m o d   G M: h(X) \bmod G \mapsto \sum_{j=0}^{\deg G-1} C[j] \cdot h(X^{p^j}) \bmod G M:h(X)modGj=0degG1C[j]h(Xpj)modG,我们称 CM 的线性化多项式(Linearized polynomials)
  • long coordinate(long i, long k),返回索引 k 的维度 i 上坐标

定义了 template <typename type> class EncryptedArrayDerived : public EncryptedArrayBase 实例化,

  • R, vec_R, mat_R, RX, vec_RX, RXModulus, RE, vec_RE, mat_RE, REX, vec_REX,公开属性,管理多项式信息
  • const Context& context,私有属性,管理各种参数
  • MappingData<type> mappingData,私有属性,管理 encode/decode slots 信息
  • rotate, shift, rotate1D, shift1D,循环右移、零填充右移,高阶立方某维度上的右移
  • encode, decode, decrypt, genericEncode, genericDecode, genericDecrypt,编码,解码,解密

定义了 class EncryptedArray,定义了多种与密文有关的接口,但是似乎自身并不存储密文。

  • const PAlgebraMod& alMod,私有属性,支持 Z p r [ X ] \mathbb Z_{p^r}[X] Zpr[X] 上的 encode/decode slots 过程
  • ClonedPtr<EncryptedArrayBase> rep,私有属性
  • EncryptedArray(const Context& context, const NTL::ZZX& G = NTL::ZZX(1, 1)),构造函数,默认情况下的明文空间是明文槽 Z p r [ X ] / ( F t ) \mathbb Z_{p^r}[X]/(F_t) Zpr[X]/(Ft) 的(同构意义下)子环 Z p r [ X ] / ( X ) ≅ Z p r \mathbb Z_{p^r}[X]/(X) \cong \mathbb Z_{p^r} Zpr[X]/(X)Zpr,必要时手动设置 G = F 1 G=F_1 G=F1
  • rotate, shift, rotate1D, shift1D,循环右移、零填充右移,高阶立方某维度上的右移
  • encode, decode,若干个编码/解码函数
  • encrypt, decrypt, decryptReal, decryptComplex,若干个加密/解密函数
  • void encodeUnitSelector(EncodedPtxt& eptxt, long i),设置位置 i 的掩码选择器

首先定义了 class PlaintextArrayDerived : public PlaintextArrayBase,它携带 std::vector<RX> data 属性存储数据。接着定义了 class PlaintextArray(弃用) 和 class PtxtArray(建议),包含了运算接口:

  • const EncryptedArray& ea,公开属性,定义了加密接口
  • PlaintextArray pa,公开属性,用于存储明文数据
  • void encode(EncodedPtxt& eptxt, double mag = -1, OptLong prec = OptLong()),利用 eapa 编码
  • void encrypt(Ctxt& ctxt, double mag = -1, OptLong prec = OptLong()),利用 eapa 加密(Ctxt 携带属性 PubKey
  • void decrypt(const Ctxt& ctxt, const SecKey& sKey, OptLong prec = OptLong()),利用 eapa 解密(额外输入 SecKey
  • load, store,读写 GF2X, ZZX, vector<long>, vector<double> 等数据
  • buildLinPolyCoeffs,根据线性变换 L 构造线性化多项式 C

定义了一些关于 PtxtArray 的自由函数,

  • ==, !=, +=, -=, *=,明文的基本运算
  • rotate, shift, rotate1D, shift1D,循环右移、零填充右移,高阶立方某维度上的右移
  • frobeniusAutomorph, conjugate, extractRealPart, extractImPart,自同构映射
  • totalSums, runningSums, power,高级的加法/乘法

定义了一些关于 EncryptedArray 的自由函数,

  • totalSums, runningSums,高级的同态加法/乘法
  • void mapTo01(const EncryptedArray& ea, Ctxt& ctxt, bool multithread = true),判断 ctxt 各个明文槽是否是零
  • void incrementalZeroTest(Ctxt* res[], const EncryptedArray& ea, const Ctxt& ctxt, long n),专用于 p − 2 , r = 1 p-2,r=1 p2,r=1 的情况,密文 res[i] 的第 j 个槽是零,如果 ctxt 的第 j 个槽的前 0...i 比特是否都是零
  • void applyLinPoly1(const EncryptedArray& ea, Ctxt& ctxt, const std::vector<NTL::ZZX>& C),将生成的映射 C = ea.buildLinPolyCoeffs 作用到 ctxt 的所有槽上
  • void applyLinPolyMany(const EncryptedArray& ea, Ctxt& ctxt, const std::vector<std::vector<NTL::ZZX>>& Cvec),将若干个映射 Cvec 分别作用到 ctxt 不同的明文槽上,其中 Cvec[0...nslots-1][0...degree-1] 包含 nslots 个长度 degree 的行向量(都由 ea.buildLinPolyCoeffs 生成)

replicate.h

定义了明文槽复制/广播的接口,

  • void replicate(const EncryptedArray& ea, Ctxt& ctx, long pos),利用 O ( log ⁡ n ) O(\log n) O(logn)rotate1D,将位置 pos 的元素广播到全部的明文槽
  • void replicateAll(std::vector<Ctxt>& v, const EncryptedArray& ea, const Ctxt& ctxt, long recBound = 64, RepAuxDim* repAuxPtr = nullptr),使用混合策略(二叉树的顶部拍平,详见 [HS14]),将所有的槽分别广播到独立的密文,在默认的启发式深度 recBound 下计算复杂度约为 O ( n ) O(n) O(n)

另外还有 class ReplicateHandlerclass RepAux 等辅助工具。

Algorithm Layer

polyEval.h

定义了同态多项式计算的接口,使用了 BSGS 算法、Paterson-Stockmeyer 算法,

  • void polyEval(Ctxt& ret, const NTL::Vec<Ctxt>& poly, const Ctxt& x),同态计算明文多项式 ret = poly(x)
  • void evalPoly(const NTL::ZZX& poly),这是 Ctxt 的一个属性
  • void polyEval(Ctxt& ret, const NTL::Vec<Ctxt>& poly, const Ctxt& x),同态计算密文多项式,参数 Vec<Ctxt>& poly 记录了多项式的系数表示, r e t = ∑ i p o l y [ i ] ⋅ x i ret = \sum_i poly[i] \cdot x^i ret=ipoly[i]xi

定义了 class DynamicCtxtPowers,用于同态计算密文 c = Ctxt(X) 的幂次

  • std::vector<Ctxt> v,私有属性,记录 X i X^i Xi 的密文
  • DynamicCtxtPowers(const Ctxt& c, long nPowers),构造函数,初始化长度 nPowers 的数组,简单存储 v[0] = c
  • Ctxt& getPower(long e),如果 X e X^e Xe(存储在 v[e-1] 中)还没有被计算,那么执行同态乘法,否则直接输出已有数据
  • bool isPowerComputed(long i),判断是否预计算过

binaryArith.h

binaryArith.cpp 中实现了 class DAGnodeclass AddDAG,用于存储管理布尔加法中的进位信息(同态乘法)。

对于 CtPtrs 对象(加密布尔值的密文列表的指针),定义了一些布尔运算,

  • void binaryCond(CtPtrs& output, const Ctxt& cond, const CtPtrs& trueValue, const CtPtrs& falseValue),根据控制位 cond(在明文槽中)确定 output 各个槽的数值(挑选 trueValuefalseValue),也就是 CMux Gate 运算
  • void binaryMask(CtPtrs& binaryNums, const Ctxt& mask),根据掩码 mask(取值 0 / 1 0/1 0/1)将某些明文槽值为零
  • concatBinaryNums, splitBinaryNums,二进制数的级联和切分
  • leftBitwiseShift, bitwiseRotate,布尔电路上的移位运算
  • bitwiseXOR, bitwiseOr, bitwiseAnd, bitwiseNot,布尔电路上的逻辑运算
  • addTwoNumbers, negateBinary, subtractBinary, addManyNumbers, multTwoNumbers, fifteenOrLess4Four,布尔电路上的算术运算
  • void decryptBinaryNums(std::vector<long>& pNums, const CtPtrs& eNums, const SecKey& sKey, const EncryptedArray& ea, bool twosComplement = false, bool allSlots = true),解密二进制数的密文 eNums,获得各个槽的整数明文 pNums,参数 twosComplement 用于确定是无符号数(二进制)还是带符号数(二补码)
  • void packedRecrypt(const CtPtrs& a, const CtPtrs& b, std::vector<zzX>* unpackSlotEncoding),批量自举两个二进制数的密文

binaryCompare.h

binaryCompare.cpp 中定义了 runningSums, compProducts, compEqGt,然后用线性迭代布尔比较算法(这很慢吧)实现 compareTwoNumbersImplementation 函数。比较之前它会自动地执行 packedRecrypt,确保乘法深度足够支持比较电路。

定义了布尔比较电路,前者仅执行 comp,后者还执行了 swap,

  • void compareTwoNumbers(Ctxt& mu, Ctxt& ni, const CtPtrs& a, const CtPtrs& b, bool twosComplement = false, std::vector<zzX>* unpackSlotEncoding = nullptr),比较 a,b 大小关系,输出 m u = ( a > b ) mu=(a>b) mu=(a>b) n i = ( a < b ) ni=(a<b) ni=(a<b)
  • void compareTwoNumbers(CtPtrs& max, CtPtrs& min, Ctxt& mu, Ctxt& ni, const CtPtrs& a, const CtPtrs& b, bool twosComplement = false, std::vector<zzX>* unpackSlotEncoding = nullptr),比较 a,b 大小关系,额外输出 max ⁡ ( a , b ) \max(a,b) max(a,b) min ⁡ ( a , b ) \min(a,b) min(a,b),也就是 Swap 运算

matmul.h

这个实现考虑 “a Ctxt encoding a vector” 的线性变换:单个密文 Ctxt ctxt 加密了行矢 vector v,获得加密 v * mat 的单个密文。

首先定义了一些虚拟类 class MatMulFullclass BlockMatMulFullclass MatMul1Dclass BlockMatMul1D,用于记录对于 vector 的线性变换,细分为 “full”、“block”、“1D” 形式。

接着定义了 template <typename type> class MatMulFull_derived : public MatMulFull 实例化,

  • PA_INJECT(type),用于存储矩阵的实际数据
  • bool get(RX& out, long i, long j),获取矩阵的 mat[i,j] 元素,如果它是零元,则返回值是 true

最后定义了 class MatMulFullExecclass BlockMatMulFullExecclass MatMul1DExecclass BlockMatMul1DExec,用于实际计算矩阵乘法。以 MatMulFullExec 为例:

  • std::vector<MatMul1DExec> transforms,公开属性,存储了线性变换的信息
  • MatMulFullExec(const MatMulFull& mat, bool minimal = false),构造函数,输入 mat 存储了 NTL::zzX 形式的矩阵元素。
  • void mul(Ctxt& ctxt),密文加密行矢 v,计算它右乘矩阵 v * mat
  • void upgrade(),更新自身的缓存 struct ConstMultiplierCache

Matrix.h

这个实现考虑 “vectors of Ctxts” 的线性变换:密文向量 vector<Ctxt> Cvec 加密了多个行矢 vector<vector> vv,获得加密 vv * mat 的密文向量。

定义了 template <typename T, std::size_t N> class Tensor,其中 N 是张量的维度,只考虑了 N=1,2 的情况。

  • std::shared_ptr<std::vector<T>> elements_ptr,私有属性,顺序存储张量的各列元素
  • Tensor(std::initializer_list<std::vector<T>> lst),构造函数,输入 lst 是列表,每个列表元素是 vector<T> 向量,表示张量的某一列
  • Tensor<T, 2> getColumn(std::size_t j),获取张量的某一列
  • Tensor<T, 2> getRow(std::size_t i),获取张量的某一行
  • template <typename T2> Tensor<T, N>& entrywiseOperation(const Tensor<T2, N>& rhs, std::function<T&(T&, const T2&)> operation),将函数 operation 分别作用到张量的每个元素
  • +=, -=, hadamard, apply, transpose,张量的一些运算

最后用 template <typename T> using Matrix = Tensor<T, 2> 定义了 class Matrix

  • 15
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值