参考文献:
配置环境,
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
正式编译,
mkdir build
cd ./build
cmake -DPACKAGE_BUILD=ON -DENABLE_TEST=ON -DGMP_DIR="${GMPDIR}" -DNTL_DIR="${NTLDIR}" .. #开启一些选项
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] 解释了某些结构的设计原理。
定义了 struct CKKS
和 struct BGV
,用于确定方案的底层代数结构。
std::complex
,也就是 C \mathbb C C 的浮点数近似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) 的不可约因子安全性:
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} Q0≈2nBits,KeySwitch 矩阵列数 c c c,明文空间特征 p p p,明文槽的度数 d d d 和个数 s s s,确定出参数 m m m 的大小。定义了 struct Context::ModChainParams
,struct Context::BootStrapParams
,struct Context::SerializableContent
,分别记录密文模数、自举参数、序列化(用于读写数据)
定义了 class Context
,用于存储方案的关键信息,下面的其他模块依赖于此。
std::vector 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 digits
,私有属性,记录 Key-Switch 中的数字分解,每个 digits[i]
是多个素数的乘积ThinRecryptData rcData
,私有属性,记录 “thin” 或者 “thick” 自举信息Context(unsigned long m, unsigned long p, unsigned long r, const std::vector& gens, const std::vector& 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 zMStar
,PAlgebraMod alMod
,std::shared_ptr ea
的引用noiseBoundForUniform, noiseBoundForMod, noiseBoundForGaussian, noiseBoundForSmall, noiseBoundForHWt
,高概率的噪声估计stdDevForRecryption, boundForRecryption
,自举噪声估计void enableBootStrapping(const NTL::Vec& 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.2⋅m, α = s / q \alpha=s/q α=s/q, n = ϕ ( m ) n=\phi(m) n=ϕ(m)clearModChain, buildModChain, endBuildModChain
,构造密文模数链定义了 template
,用于构造 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()
,根据自身存储的信息,构造上下文对象定义了 class ModuliSizes
,用于根据 modulo-size 确定 primeSets
typedef std::pair Entry
,存储 (size, set-of-primes)
元组void init(const Context& context)
,初始化素数存储表IndexSet getSet4Size(double low, double high, const IndexSet& fromSet, bool reverse)
,确定指标集 formSet
中的最大子集,使得这些素数的乘积满足区间 [low, high]
定义了 class DoubleCRT
,构造 L L L 行 ϕ ( m ) \phi(m) ϕ(m) 列矩阵,第 i i i 行使用 p i p_i pi 素数执行 FFT/NTT。所包含的属性:
DoubleCRT(const NTL::ZZX& poly, const Context& _context, const IndexSet& indexSet)
,根据上下文 Context(记录了可用的素数 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(), +=, -=, *=, /=, ==, !=
,基本运算符定义了 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=dn−1dims[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
,管理高阶立方中的数据对象。
NTL::Vec 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
定义了 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 p∤m 的素数。群 ( 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,⋯,gi−1) 中拥有相同阶“ 的那些元素,群 ( 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^* T⊆Zm∗ 是商群 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:={i∏giei⋅j∏hjej ei∈[ord(gi)],ej∈[ord(hj)]}
假设 ∣ T ∣ = l |T|=l ∣T∣=l,令 d = ϕ ( m ) / l d=\phi(m)/l d=ϕ(m)/l,那么有如下分圆多项式的分解
Φ m ( X ) = ∏ t ∈ T F t ( X ) \Phi_m(X) = \prod_{t \in T} F_t(X) Φm(X)=t∈T∏Ft(X)
易知 1 ∈ T 1 \in T 1∈T,首先确定任意的不可约因子设为 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)。
class PAlgebra
的属性:
m, p, phiM, ordP, nfactors, radm, normBnd, polyNormBnd
,私有属性,管理相关参数std::vector gens
,私有属性,管理 Z m ∗ \mathbb Z_m^* Zm∗ 的生成元NTL::Vec native
,私有属性,native[i]=true
指示 gens[i]
落在子群 ( g 1 , g 2 , ⋯ ) (g_1,g_2,\cdots) (g1,g2,⋯) 内NTL::Vec frob_perturb
,私有属性,frob_perturb[i]=j
指示 gens[i]
的乘法阶为 p j p^j pjCubeSignature cube
,私有属性,管理 Z m ∗ / ( p ) \mathbb Z_m^*/(p) Zm∗/(p) 的高阶立方的结构std::vector T, Tidx
,私有属性,前者 T[i]=t
记录了各个代表元 t ∈ Z m ∗ / ( p ) t \in \mathbb Z_m^*/(p) t∈Zm∗/(p),后者 Tidx[t]=i
是反过来的std::vector zmsIdx, zmsRep
,私有属性,前者 zmsIdx[t]=i
记录了 t ∈ Z m ∗ t \in \mathbb Z_m^* t∈Zm∗ 的次序 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 ldouble 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]
的乘法阶(高阶立方 cube
第 i
维度的规模)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^* t∈Zm∗ 的索引 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
实例化,包含的属性有:
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] Ft∈R[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 crt
void mapToSlots(MappingData& mappingData, const RX& G)
,根据 G ( X ) G(X) G(X) 计算出到 slots 的映射void embedInSlots(RX& H, const std::vector& alphas, const MappingData& mappingData)
,将 [ α 0 , ⋯ , α l − 1 ] [\alpha_0,\cdots,\alpha_{l-1}] [α0,⋯,αl−1] 编码到 H ∈ R [ X ] / ( Φ m ( X ) ) H \in R[X]/(\Phi_m(X)) H∈R[X]/(Φm(X)) 的 slots 上class PAlgebraMod
就是某个 PAlgebraModBase
对象实例的指针,
ClonedPtr rep
,私有属性explicit PAlgebraMod(const PAlgebra& zMStar, long r)
,根据 A p \mathbb A_p Ap 和 r r r 构造 A p r \mathbb A_{p^r} Aprconst PAlgebra& getZMStar()
,返回底层的 PAlgebra
结构(在 rep
里存储)const std::vector& getFactorsOverZZ()
,返回 Φ m ( X ) ( m o d p r ) \Phi_m(X) \pmod{p^r} Φm(X)(modpr) 的分解(在 rep
里存储)使用 typedef NTL::Vec
描述简单置换 p [ i ] = π i p[i] = \pi_i p[i]=πi,
void applyPermToVec(std::vector& out, const std::vector& 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& out, const std::vector& 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
,用于置换高阶立方的某一列
定义了 class GeneralBenesNetwork
,使用 Benes Network 实现任意的置换(自同构仅提供简单的移位置换)
定义了 template
,代数结构 Z m ∗ / ( p ) \mathbb Z_m^*/(p) Zm∗/(p) 的各个生成元,都需要一棵完全二叉树,用于高阶立方各个维度的任意置换
定义了 class PermNetwork
,这是一个 “背靠背” 蝴蝶网络,
NTL::Vec layers
,私有属性,记录了置换网络的各层信息PermNetwork(const Permut& pi, const GeneratorTrees& trees)
,根据映射 pi
构造置换网络void applyToCtxt(Ctxt& c, const EncryptedArray& ea)
,密文槽的同态置换定义了 class PermIndepPrecomp
和 class PermPrecomp
,前者是 permutation-independent 预计算,后者是 permutation-dependent 预计算。
定义了 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)
,打印环结构的参数定义了 class PolyMod
,用于存储 Z p r [ X ] / ( G ( X ) ) \mathbb Z_{p^r}[X]/(G(X)) Zpr[X]/(G(X)) 中的多项式。
PolyMod(const std::vector& input, const std::shared_ptr& ringDescriptor)
,根据 PolyModRing 将系数表示(input[i]
表示 x i x^i xi 的系数)转化为环元素==, !=, -, *, +, -, *=, +=, -=
,基本运算friend std::ostream& operator<<(std::ostream& os, const PolyMod& poly)
,打印多项式定义了 class EncryptedArrayBase
,这是 virtual
的类,用于明文槽的数据移动
getContext, getPAlgebra, getDegree, getP2R
,获取相关参数rotate, shift, rotate1D, shift1D
,右旋、右移encode, decode
,数组和多项式之间的转换decrypt, rawDecrypt, decryptComplex, rawDecryptComplex, rawDecryptReal, decryptReal
,解密函数void buildLinPolyCoeffs(std::vector& C, const std::vector& L)
,根据线性映射 L
构造线性多项式列表 C
,两者都是公开的多项式
L
描述了 M
对于标准 Power Basis 的作用C
是 M
的线性化多项式(Linearized polynomials)long coordinate(long i, long k)
,返回索引 k
的维度 i
上坐标定义了 template
实例化,
R, vec_R, mat_R, RX, vec_RX, RXModulus, RE, vec_RE, mat_RE, REX, vec_REX
,公开属性,管理多项式信息const Context& context
,私有属性,管理各种参数MappingData 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 rep
,私有属性rotate, shift, rotate1D, shift1D
,循环右移、零填充右移,高阶立方某维度上的右移encode, decode
,若干个编码/解码函数encrypt, decrypt, decryptReal, decryptComplex
,若干个加密/解密函数首先定义了 class PlaintextArrayDerived : public PlaintextArrayBase
,它携带 std::vector
属性存储数据。接着定义了 class PlaintextArray
(弃用) 和 class PtxtArray
(建议),包含了运算接口:
const EncryptedArray& ea
,公开属性,定义了加密接口PlaintextArray pa
,公开属性,用于存储明文数据void encode(EncodedPtxt& eptxt, double mag = -1, OptLong prec = OptLong())
,利用 ea
将 pa
编码void encrypt(Ctxt& ctxt, double mag = -1, OptLong prec = OptLong())
,利用 ea
将 pa
加密(Ctxt
携带属性 PubKey
)void decrypt(const Ctxt& ctxt, const SecKey& sKey, OptLong prec = OptLong())
,利用 ea
将 pa
解密(额外输入 SecKey
)load, store
,读写 GF2X, ZZX, vector, vector
等数据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 p−2,r=1 的情况,密文 res[i]
的第 j
个槽是零,如果 ctxt
的第 j
个槽的前 0...i
比特是否都是零void applyLinPoly1(const EncryptedArray& ea, Ctxt& ctxt, const std::vector& C)
,将生成的映射 C = ea.buildLinPolyCoeffs
作用到 ctxt
的所有槽上void applyLinPolyMany(const EncryptedArray& ea, Ctxt& ctxt, const std::vector>& Cvec)
,将若干个映射 Cvec
分别作用到 ctxt
不同的明文槽上,其中 Cvec[0...nslots-1][0...degree-1]
包含 nslots
个长度 degree
的行向量(都由 ea.buildLinPolyCoeffs
生成)定义了明文空间的一些功能,
std::vector convertDataToSlotVector(const std::vector& data, const Context& context)
,
vector
转换为 vector
,这里的 From
可以是 NTL::ZZX
vector
转换为 vector>
,这里的 From
可以是 double
定义了 template
,
explicit Ptxt(const Context& context)
,根据上下文初始化Ptxt(const Context& context, const SlotType& value)
,将明文槽都设置为 value
template Ptxt(const Context& context, const std::vector& 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& random()
,清理明文、随机明文const std::vector& getSlotRepr()
,获取明文的 slots 表示NTL::ZZX getPolyRepr()
,获取明文的 coeff 表示void encode(EncodedPtxt& eptxt, double mag = -1, OptLong prec = OptLong())
,将自身(solts 形式)编码为 EncodedPtxt
(poly 形式)==, !=, *, +, -, *=, +=, -=, negate
,基本运算Ptxt& addConstant(const Scalar& scalar)
,全部明文槽都加常数,BGV 专用Ptxt& addConstantCKKS(const Scalar& scalar)
,全部明文槽都加常数,CKKS 专用multiplyBy, multiplyBy2, square, cube, power
,乘法、幂次Ptxt& rotate(long amount)
,循环右移,槽 i
移动到 i+amount mod size
Ptxt& rotate1D(long dim, long amount)
,高阶立方体 dim
维度上的循环右移,是由 Z m ∗ \mathbb Z_m^* Zm∗ 的循环群结构 PAlgebra& zMStar = context->getZMStar()
所诱导的Ptxt& shift(long amount)
,零填充右移Ptxt& shift1D(long dim, long amount)
,高阶立方体 dim
维度上的零填充右移Ptxt& 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^* k∈Zm∗Ptxt& 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& replicate(long pos)
,第 pos
个明文槽的广播复制complexConj, real, imag
,复数变换,CKKS 专用runningSums, totalSums
,明文槽加和,前者是前缀槽的和,后者是全部槽的和incrementalProduct, totalProduct
,明文槽乘积,前者是前缀槽的积,后者是全部槽的积定义了 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_BGV
和 EncodedPtxt_CKKS
对象引用eptxt.resetBGV(), eptxt.resetCKKS()
,重置 EncodedPtxt_BGV
和 EncodedPtxt_CKKS
对象定义了 FatEncodedPtxt_BGV
,class FatEncodedPtxt_CKKS
和 class FatEncodedPtxt
,接口是一样的,但是存储结构为 DoubleCRT dcrt
定义了 class SKHandle
,用于描述满足形式 s r ( X t ) s^r(X^t) sr(Xt) 的私钥元素(没看懂这是干嘛的),属性 powerOfS, powerOfX, secretKeyID
(并没有存储私钥数据,是仅描述位置信息么)
定义了 class CtxtPart : public DoubleCRT
,用于存储密文中的单个多项式,包含一个 SKHandle
对象,并继承了 DoubleCRT
的属性(以 DCRT 格式存储和计算)
定义了 class Ctxt
,使用 std::vector
对象来存储密文 c[i] = part[i]
,
context, pubKey
,私有属性,密文相关参数的指针parts, primeSet, ptxtSpace, noiseBound
,私有属性,存储密文各个分量、用到的素数、明文模数、平均噪声估计intFactor, ratFactor, ptxtMag
,私有属性,前者用于 BGV 纠错,后两者用于 CKKS 纠错(尾数部分,指数部分)tensorProduct, subPart, addPart, keySwitchPart, keySwitchDigits
,私有属性,用于同态运算==, !=
,检查两个 Ctxt
对象的 size, primeSet, intFactor, noiseBound
是否相同negate, +=, -=, *=
,基本的同态运算xorConstant, nxorConstant
,根据公式 a ⊕ b = a + b − 2 a b a \oplus b = a+b-2ab a⊕b=a+b−2ab 和 ( a ⊕ b ) ‾ = 1 − a − b + 2 a b \overline{(a \oplus b)}=1-a-b+2ab (a⊕b)=1−a−b+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)=1void smartAutomorph(long k)
,计算自同构,紧接着执行重线性化void frobeniusAutomorph(long j)
,也就是 smartAutomorph(p^j mod m)
divideByP, multByP
,简单作用到密文上,使得明文模数分别变为 p r − 1 , r > 1 p^{r-1},r>1 pr−1,r>1 和 p r + 1 , r ≥ 1 p^{r+1},r\ge1 pr+1,r≥1multiplyBy, multiplyBy2, square, cube, power
,高等同态乘法void evalPoly(const NTL::ZZX& poly)
,执行同态多项式求值reducePtxtSpace, hackPtxtSpace
,模切换过程,后者在明文高位引入噪声void Ctxt::reLinearize(long keyID)
,重线性化过程,keyID
确定要切换到的私钥 ( 1 , s i ) (1,s_i) (1,si)void blindCtxt(const NTL::ZZX& poly)
,盲化 BGV 密文,加上常数 poly
的高噪声密文NTL::xdouble modSwitchAddedNoiseBound()
,估计模切换带来的额外噪声modUpToSet, modDownToSet, bingToSet
,模切换过程,后者先 Up
再 Down
void dropSmallAndSpecialPrimes()
,移除 Key-Switch 过程的副作用(密文模数放大了 SpecialPrimes
),同时会自动添加一些 ctxtPrimes
使得模切换的额外噪声可忽略totalNoiseBound, errorBound
,前者估计相位中的噪声(CKKS 要加上 ptxtMag * ratFactor
精度损失),后者估计明文中的噪声(BGV 的是零)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& 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} pr−j,但是这些密文的 Level 相同extractBits, extendExtractDigits
,其他的数字分解void CheckCtxt(const Ctxt& c, const char* label)
,打印密文的错误信息定义了同态多项式计算的接口,使用了 BSGS 算法、Paterson-Stockmeyer 算法,
void polyEval(Ctxt& ret, const NTL::Vec& poly, const Ctxt& x)
,同态计算明文多项式 ret = poly(x)
void evalPoly(const NTL::ZZX& poly)
,这是 Ctxt
的一个属性void polyEval(Ctxt& ret, const NTL::Vec& poly, const Ctxt& x)
,同态计算密文多项式,参数 Vec& 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 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)
,判断是否预计算过定义了 class PubKey
,管理公钥数据以及相关接口,
Ctxt pubEncrKey
,私有属性,公钥就是零的密文 p k = R L W E s ( 0 ) pk = RLWE_s(0) pk=RLWEs(0)std::vector keySwitching
,私有属性,记录了多个秘钥切换矩阵 W [ s ′ → s ] W[s' \to s] W[s′→s]std::vector> keySwitchMap
,私有属性,这是个指针数组,keySwitchMap[i][n] = j
记录了对 s i ( X n ) s_i(X^n) si(Xn) 重线性化时应当使用 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 sKeys
,私有属性,存储了 s k = s sk=s sk=sGenSecKey, 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
是典范嵌入的无穷范数。
有两种 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[s′→s]=(a,b)T∈Rq2×t 的 KSK 矩阵
SKHandle fromKey
和 long toKeyID
,分别记录了 s ′ s' s′ 和 s s s 的句柄/索引NTL::ZZ prgSeed
和 std::vector b
,分别记录了 a ⃗ \vec a a(PRG seed)和 b ⃗ \vec b b在 SecKey
内构造添加 KeySwitch
的自由函数,
void addAllMatrices(SecKey& sKey, long keyID = 0)
,生成所有映射 s ( X e ) ↦ s ( X ) , ∀ e ∈ Z m ∗ s(X^e) \mapsto s(X), \forall e \in \mathbb Z_m^* s(Xe)↦s(X),∀e∈Zm∗ 的 KSK 矩阵void addFewMatrices(SecKey& sKey, long keyID = 0)
,生成少量映射的 KSK 矩阵,确保 s ( X e ) ↦ s ( X ) , ∀ e ∈ Z m ∗ s(X^e) \mapsto s(X), \forall e \in \mathbb Z_m^* s(Xe)↦s(X),∀e∈Zm∗ 都可以两步以内被线性化(看不懂)void add1DMatrices(SecKey& sKey, long keyID = 0)
,生成全部形如 s ( X g ± i ) ↦ s ( X ) s(X^{g^{\large{\pm i}}}) \mapsto s(X) s(Xg±i)↦s(X) 映射的 KSK 矩阵,其中 Z m ∗ / ( p ) = ( g ) \mathbb Z_m^*/(p) = (g) Zm∗/(p)=(g) 且 i < o r d ( g ) ivoid addFrbMatrices(SecKey& sKey, long keyID = 0)
,生成全部形如 s ( X p i ) ↦ s ( X ) s(X^{p^i}) \mapsto s(X) s(Xpi)↦s(X) 映射的 KSK 矩阵void addMatrices4Network(SecKey& sKey, const PermNetwork& net, long keyID = 0)
,生成置换网络 net
所需的那些 KSK 矩阵定义了一些关于 G F ( p d ) GF(p^d) GF(pd) 上明文槽的 Packing/Unpacking 功能,
void buildUnpackSlotEncoding(std::vector& 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& unpackSlotEncoding)
,解包函数BGV 存在 [HS15], [CH18] 两种自举算法。
定义了 class RecryptData
,用于存储自举相关的数据
NTL::Vec mvec
,参数 m m m 的素分解e, ePrime, skHwt
,明文空间、私钥重量alMod, ea
,明文槽的结构和编码解码接口init, setAE
,配置自举数据定义了 class ThinRecryptData : public RecryptData
,专用于 “thin” bootstrapping 的自举数据。
在 recryption.cpp
中定义了一些没有在 recryption.h
内声明的自由函数,可能包含在其他的头文件里,
extractDigitsPacked
和 extractDigitsThin
,同态数字提取void PubKey::reCrypt(Ctxt& ctxt)
和 void PubKey::thinReCrypt(Ctxt& ctxt)
,单个密文的自举程序void packedRecrypt(const CtPtrs& cPtrs, const std::vector& unpackConsts, const EncryptedArray& ea)
,利用 repack, unpack
将 CtPtrs
中的每 deg d \deg d degd 个密文打包在一起,批量自举在 binaryArith.cpp
中实现了 class DAGnode
和 class AddDAG
,用于存储管理布尔加法中的进位信息(同态乘法)。
对于 CtPtrs
对象(加密布尔值的密文列表的指针),定义了一些布尔运算,
void binaryCond(CtPtrs& output, const Ctxt& cond, const CtPtrs& trueValue, const CtPtrs& falseValue)
,根据控制位 cond
(在明文槽中)确定 output
各个槽的数值(挑选 trueValue
或 falseValue
),也就是 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& 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* unpackSlotEncoding)
,批量自举两个二进制数的密文在 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* unpackSlotEncoding = nullptr)
,比较 a,b
大小关系,输出 m u = ( a > b ) mu=(a>b) mu=(a>b) 和 n i = ( a < b ) ni=(ani=(a<b)void compareTwoNumbers(CtPtrs& max, CtPtrs& min, Ctxt& mu, Ctxt& ni, const CtPtrs& a, const CtPtrs& b, bool twosComplement = false, std::vector* unpackSlotEncoding = nullptr)
,比较 a,b
大小关系,额外输出 max ( a , b ) \max(a,b) max(a,b) 和 min ( a , b ) \min(a,b) min(a,b),也就是 Swap 运算用于多线程的加锁和同步,
std::atomic_long, std::atomic_ulong
,原子的整数类型std::mutex, std::lock_guard
,资源锁BGV 方案的 SIMD 技术,
代码示例
#include
int main(){
return 0;
}
编写 CMakeLists.txt
,编译执行
CKKS 方案的 SIMD 技术,
代码示例
#include
int main(){
return 0;
}