GSW方案是由Craig Gentry1, Amit Sahai与Brent Waters于2013年提出的方案, 发表于论文[GSW13] 2中.
GSW方案确实如论文标题一样, 概念清晰明了, 其Intuition简单到一个刚学完线性代数的大一新生也能理解. GSW还支持基于属性的加密, 但本文中我们将不介绍这一部分内容.
当然, 完全理解GSW方案仍然需要用到一些比较进阶的知识, 如LWE问题的困难性等. 我们在本文中不会对这些知识做过多的介绍, 这些知识将在今后其他的博文中介绍. 关于同态加密的基础知识可以参阅博文同态加密(0) 基础概念, 这篇博文完成后, 地址将被更新到这里.
最基本的GSW同态加密方案的私钥( s k sk sk)是一个向量 v ∈ Z q N \mathbf v\in\mathbb Z_q^N v∈ZqN3, 而所有的明文 μ i ∈ { 0 , 1 } \mu_i\in\{0,1\} μi∈{0,1}都被加密一个矩阵 C i ∈ Z q N × N C_i\in\mathbb Z_q^{N\times N} Ci∈ZqN×N中, 其中 C i C_i Ci是以 v v v为近似特征向量并以 μ i \mu_i μi为近似特征值的矩阵, 即我们要求
C i v ≈ μ i v C_i\mathbf v\approx \mu_i \mathbf v Civ≈μiv
这里可以看出, 我们只需要挑选 v \mathbf v v中非 0 0 0的位(最好是选较大的位), 如第 j j j位 v j v_j vj, 并比较 v j v_j vj与 μ i v j \mu_iv_j μivj的值就可以解出 μ i \mu_i μi的值.
一个需要注意的地方就是, 虽然 μ i \mu_i μi取自 { 0 , 1 } \{0,1\} {0,1}, 但被视作是 Z q \mathbb Z_q Zq中的元素, 因此具体的运算也是按照 Z q \mathbb Z_q Zq的运算方式来进行.
我们也可以将噪声(error)显式地写出来, 记作
C i v = μ i v + e C_i\mathbf v=\mu_i\mathbf v+\mathbf e Civ=μiv+e
其中 e \mathbf e e是非常小的向量. 因此可以看出, 如果 e \mathbf e e确实是一个较小的噪声, 那么我们就可以正确地解出 μ i \mu_i μi.
现在我们来验证该加密方案具有同态性质. 现在假设有两个密文 C 1 , C 2 C_1, C_2 C1,C2, 对对应的明文分别是 μ 1 , μ 2 \mu_1,\mu_2 μ1,μ2, 即
C 1 v = μ 1 v + e 1 C 2 v = μ 2 v + e 2 C_1\mathbf v=\mu_1\mathbf v+\mathbf e_1\\ C_2\mathbf v=\mu_2\mathbf v+\mathbf e_2\\ C1v=μ1v+e1C2v=μ2v+e2
其中 e 1 , e 2 \mathbf e_1,\mathbf e_2 e1,e2均为较小的噪声, 那么令 C × = C 1 ⋅ C 2 C^\times=C_1\cdot C_2 C×=C1⋅C2, 我们检验 C × C^\times C×的解密结果
C × v = ( C 1 ⋅ C 2 ) v = C 1 ( μ 2 v + e 2 ) = μ 2 ( μ 1 v + e 1 ) + C 1 e 2 = μ 1 μ 2 v + μ 2 e 1 + C 1 e 2 \begin{aligned} C^\times\mathbf v &=(C_1\cdot C_2)\mathbf v=C_1(\mu_2\mathbf v+\mathbf e_2)=\mu_2(\mu_1\mathbf v+\mathbf e_1)+C_1\mathbf e_2\\ &= \mu_1\mu_2\mathbf v+\mu_2\mathbf e_1+C_1\mathbf e_2 \end{aligned} C×v=(C1⋅C2)v=C1(μ2v+e2)=μ2(μ1v+e1)+C1e2=μ1μ2v+μ2e1+C1e2
这里可以看出, μ 2 e 1 \mu_2\mathbf e_1 μ2e1确实是一个比较小的噪声项, 但是要让 C × C^\times C×的噪声比较小, 那么就需要让 C 1 C_1 C1是一个较小的矩阵(即其最大的元素较小), 我们稍后会解释如何做到这一点.
虽然说是乘法同态性质, 但是由于 μ i ∈ { 0 , 1 } \mu_i\in\{0,1\} μi∈{0,1}, 我们也可以将 C × C^\times C×视作是做了同态的与(AND)运算. 与运算相对来说是比较简单的, 但是仅有与运算是不够的, 因为与运算是单调的, 单调的电路不可能是完备的, 我们需要实现一个超强的逻辑门----与非门的同态运算.
设 C N A N D = I N − C 1 C 2 C^\mathsf{NAND}=I_N-C_1C_2 CNAND=IN−C1C2, 其中 I N I_N IN为 N N N阶单位矩阵, 则
C N A N D v = ( I N − C 1 C 2 ) v = ( 1 − μ 1 μ 2 ) v − μ 2 e 1 − C 1 e 2 C^\mathsf{NAND}\mathbf v=(I_N-C_1C_2)\mathbf v=(1-\mu_1\mu_2)\mathbf v-\mu_2\mathbf e_1-C_1\mathbf e_2 CNANDv=(IN−C1C2)v=(1−μ1μ2)v−μ2e1−C1e2
根据之前的讨论, 如果 C 1 C_1 C1是一个较小的项, 我们有把握能从 C N A N D C^\mathsf{NAND} CNAND中解出 N A N D ( μ 1 , μ 2 ) \mathsf{NAND}(\mu_1,\mu_2) NAND(μ1,μ2).
到这里有没有一种心情舒畅的感觉? 与非门生万物, 我们确实可以通过不断地叠加与非门来实现相当复杂的函数运算, 并且由于与非门是完备的, 仅用与非门可以实现任何一个布尔函数.
虽然与非门非常强大, 但是每一次进行与非门运算, 都会导致新密文得噪声变得更大, 因此较多层的运算后, 噪声可能大得导致解密错误! 因此我们必须评估我们究竟能进行多少次的运算, 以及在快要达到极限的时候使用Bootstrapping技术. 这一点我们将在详细介绍方案的时候来说明.
这里我们要首先介绍一种工具, 我们称其为Lattice Gadget, 它的本质是一些代数运算, 能够辅助我们从标准的LWE加密方案生成满足同态性质的密文.
第一个运算是 B i t D e c o m p \mathsf{BitDecomp} BitDecomp, 它的作用是将一个 a = ( a 1 , ⋯   , a n ) ∈ Z q n \mathbf a=(a_1,\cdots,a_n)\in\mathbb Z_q^n a=(a1,⋯,an)∈Zqn4向量的每一位按照二进制展开, 即每一个元素 a i a_i ai表示成二进制的形式 a 0 , a 1 , ⋯   , a ℓ a_0,a_1,\cdots,a_\ell a0,a1,⋯,aℓ, 其中 ℓ = ⌊ log q ⌋ + 1 \ell=\lfloor\log q\rfloor+1 ℓ=⌊logq⌋+15. 即
B i t D e c o m p ( a ) = ( a 1 , 0 , ⋯   , a 1 , ℓ − 1 , ⋯   , a n , 0 , ⋯   , a n , ℓ − 1 ) \mathsf{BitDecomp}(\mathbf a)=(a_{1,0},\cdots,a_{1,\ell-1},\cdots,a_{n,0},\cdots,a_{n,\ell-1}) BitDecomp(a)=(a1,0,⋯,a1,ℓ−1,⋯,an,0,⋯,an,ℓ−1)
即将 a \mathbf a a的每一位都展开成了二进制, 变成 ℓ \ell ℓ位, 整个结果一共是 n ⋅ ℓ n\cdot \ell n⋅ℓ位. 显然, a i = ∑ j = 0 ℓ − 1 2 j ⋅ a i , j a_i=\sum_{j=0}^{\ell-1} 2^j\cdot a_{i,j} ai=∑j=0ℓ−12j⋅ai,j.
类似的, 我们可以定义 B i t D e c o m p \mathsf{BitDecomp} BitDecomp的反函数 B i t D e c o m p − 1 \mathsf{BitDecomp}^{-1} BitDecomp−1, 令 a ′ = ( a 1 , 0 , ⋯   , a 1 , ℓ , ⋯   , a n , 0 , ⋯   , a n , ℓ ) ∈ Z q n ⋅ ℓ \mathbf a'=(a_{1,0},\cdots,a_{1,\ell},\cdots,a_{n,0},\cdots,a_{n,\ell})\in\mathbb Z_q^{n\cdot \ell} a′=(a1,0,⋯,a1,ℓ,⋯,an,0,⋯,an,ℓ)∈Zqn⋅ℓ
B i t D e c o m p − 1 ( a ′ ) = ( ∑ j = 0 ℓ − 1 2 j ⋅ a 1 , j , ⋯   , ∑ j = 0 ℓ − 1 2 j ⋅ a n , j ) \mathsf{BitDecomp}^{-1}(\mathbf a')=(\sum_{j=0}^{\ell-1} 2^j\cdot a_{1,j},\cdots, \sum_{j=0}^{\ell-1} 2^j\cdot a_{n,j}) BitDecomp−1(a′)=(j=0∑ℓ−12j⋅a1,j,⋯,j=0∑ℓ−12j⋅an,j)
即将每一位的二进制表示重新组合成了 Z q \mathbb Z_q Zq表示. 但是要注意的是, B i t D e c o m p \mathsf{BitDecomp} BitDecomp并没有要求参数一定要是只由 { 0 , 1 } \{0,1\} {0,1}构成的向量, 我们可以定义一个全新的函数
F l a t t e n ( a ′ ) = B i t D e c o m p ( B i t D e c o m p − 1 ( a ′ ) \mathsf{Flatten}(\mathbf a')=\mathsf{BitDecomp}(\mathsf{BitDecomp}^{-1}(\mathbf a') Flatten(a′)=BitDecomp(BitDecomp−1(a′)
这个操作有什么意义? 它将那些不是全由 { 0 , 1 } \{0,1\} {0,1}构成的 a ′ ∈ Z n ⋅ ℓ \mathbf a'\in\mathbb Z^{n\cdot \ell} a′∈Zn⋅ℓ重新"抹平"成了由 { 0 , 1 } \{0,1\} {0,1}中的元素构成, 并且能够保持其一定的性质.
下面介绍另一个不是那么好看, 但是却非常简单的操作 P o w e r o f 2 \mathsf{Powerof2} Powerof2. P o w e r o f 2 \mathsf{Powerof2} Powerof2的功能也是将一个 b ∈ Z q n \mathbf b\in\mathbb Z_q^n b∈Zqn向量转换为 b ′ ∈ Z q n ⋅ ℓ \mathbf b'\in\mathbb Z_q^{n\cdot \ell} b′∈Zqn⋅ℓ向量, 但是却使用的是完全不一样的方式.
P o w e r o f 2 ( b ) = ( b 1 , 2 b 1 , ⋯   , 2 ℓ − 1 b 1 , ⋯   , b n , 2 b n , ⋯   , 2 ℓ − 1 b n ) \mathsf{Powerof2}(\mathbf b)=(b_1,2b_1,\cdots,2^{\ell-1}b_1,\cdots, b_n,2b_n,\cdots,2^{\ell-1}b_n) Powerof2(b)=(b1,2b1,⋯,2ℓ−1b1,⋯,bn,2bn,⋯,2ℓ−1bn)
即将 b \mathbf b b的每一位, 展开为 ℓ \ell ℓ位, 并且后一位是前一位的两倍. 使得整个向量变成 b ′ \mathbf b' b′. 这样做的好处是, 如果 a i , b i a_i,b_i ai,bi分别是 a , b ∈ Z q n \mathbf a,\mathbf b\in\mathbb Z_q^n a,b∈Zqn中的一位, 那么
a i ⋅ b i = ∑ j = 1 ℓ − 1 2 j ⋅ a i , j ⋅ b i = ∑ j = 1 ℓ − 1 ( a i , j ) ⋅ ( 2 j ⋅ b j ) a_i\cdot b_i=\sum_{j=1}^{\ell -1}2^j \cdot a_{i,j}\cdot b_i=\sum_{j=1}^{\ell-1}(a_{i,j})\cdot (2^{j}\cdot b_j) ai⋅bi=j=1∑ℓ−12j⋅ai,j⋅bi=j=1∑ℓ−1(ai,j)⋅(2j⋅bj)
前面一部分就是 a ′ \mathbf a' a′中第 i i i组的第 j j j位, 而后一部分就是 b ′ \mathbf b' b′中第 i i i组的第 j j j位, 那么显然有
KaTeX parse error: Expected 'EOF', got '\ranglet' at position 102: …of2}(\mathbf b)\̲r̲a̲n̲g̲l̲e̲t̲ ̲
如果将 B i t D e c o m p ( a ) \mathsf{BitDecomp}(\mathbf a) BitDecomp(a)直接写成 a ′ \mathbf a' a′的形式, 我们还有
⟨ a ′ , P o w e r o f 2 ( b ) ⟩ = ⟨ B i t D e c o m p − 1 ( a ′ ) , b ⟩ = ⟨ F l a t t e n ( a ′ ) , P o w e r o f 2 ( b ) ⟩ \langle\mathbf a',\mathsf{Powerof2}(\mathbf b)\rangle=\langle\mathsf{BitDecomp}^{-1}(\mathbf a'),\mathbf b\rangle=\langle \mathsf{Flatten}(\mathbf a'),\mathsf{Powerof2}(\mathbf b)\rangle ⟨a′,Powerof2(b)⟩=⟨BitDecomp−1(a′),b⟩=⟨Flatten(a′),Powerof2(b)⟩
实际上左右两边的两项都是由中间得到的, 这样就可以将左右两边连接在一起. 这样我们发现一个惊人的事实: 如果内积的第二项是标准的 P o w e r o f 2 \mathsf{Powerof2} Powerof2结果的形式, 那么对第一项做 F l a t t e n \mathsf{Flatten} Flatten操作不会改变内积的结果! 实际上这也不难理解, 因为Flatten操作就是把数值过高的位分到权重更高的位而已. 但是这样做有一个好处就是, 使得 a ′ \mathbf a' a′变成每一位都是 { 0 , 1 } \{0,1\} {0,1}的 F l a t t e n ( a ′ ) \mathsf{Flatten}({\mathbf a'}) Flatten(a′).
我们将以上几种记号都推广到对矩阵可用, 例如对于 C = [ c 1 , ⋯   , c N ] C=[\mathbf c_1,\cdots,\mathbf c_N] C=[c1,⋯,cN], 令
F l a t t e n ( C ) = [ F l a t t e n ( c 1 ) , ⋯   , F l a t t e n ( c N ) ] \mathsf{Flatten}(C)=[\mathsf{Flatten}(\mathbf c_1),\cdots,\mathsf{Flatten}(\mathbf c_N)] Flatten(C)=[Flatten(c1),⋯,Flatten(cN)]
其余几种记号也做类似的推广, 总之就是, 对矩阵的每一列的列向量做相应的操作. 这时我们发现, 如果密钥 v \mathbf v v确实是某个向量 s \mathbf s s进行 P o w e r o f 2 \mathsf{Powerof2} Powerof2的结果, 即 v = P o w e r o f 2 ( s ) \mathbf v=\mathsf{Powerof2}(s) v=Powerof2(s), 那么就有
C i v = F l a t t e n ( C i ) v C_i\mathbf v=\mathsf{Flatten}(C_i)\mathbf v Civ=Flatten(Ci)v
这可以使得 C i ′ = F l a t t e n ( C i ) C_i'=\mathsf{Flatten}(C_i) Ci′=Flatten(Ci)变成一个较小的矩阵, 而不改变最后与 v \mathbf v v的相乘的结果! 这样使得 C i ′ C'_i Ci′可以代替 C i C_i Ci进行下一层的同态运算使得我们要求的 C 2 C_2 C2项较小! 我们直接将 N A N D \mathsf{NAND} NAND的结果记作
C N A N D = F l a t t e n ( I N − C 1 C 2 ) C^{\mathsf{NAND}}=\mathsf{Flatten}(I_N-C_1C_2) CNAND=Flatten(IN−C1C2)
现在我们开始具体介绍方案. 我们要说的是, GSW方案根据解密算法的选区不同, 实际上有构造两套方案. 第一种是选择 D e c \mathsf{Dec} Dec作为解密算法, 该算法仅能解出 μ i ∈ { 0 , 1 } \mu_i\in\{0,1\} μi∈{0,1}, 因此整个同态运算中主要用与非门构建逻辑电路进行计算. 另一个解密算法 M P D e c \mathsf{MPDec} MPDec可以解出 μ i ∈ Z q \mu_i\in\mathbb Z_q μi∈Zq, 这样就可以自然地使用加法与乘法进行运算.
首先我们要说的是, GSW并不是一个标准假设下的全同态加密方案. GSW如果要做到全同态加密, 需要用到Bootstrapping, 进而需要用到LWE加密方案的Circular Security假设(即用一对公私钥中的公钥来加密私钥相关信息的加密结果是安全的). 我们这里不介绍Bootstrapping的具体过程, 仅介绍Somewhat HE.
这里的参数较多, 需要逐一解释一下. 首先 λ \lambda λ是安全参数, 表示密码方案中基于的困难的问题的复杂程度, 所有的参数都应该(直接或间接)基于这个参数选择. 参数 L L L表示同态运算的层数, 由于同态运算的层数由噪声的占比决定, 因此想要做更多的同态运算次数, 那么噪声就不应该太快掩盖 q q q, q q q就应该相应地选择大一些. 而LWE问题的错误分布 χ \chi χ还有维数 n n n按理来说是应该根据 λ \lambda λ来选择, 但是这两个参数是可以根据 q q q来进行权衡(tradeoff)的, 这里直接用基础参数 L L L来代替 q q q. 而参数 ℓ , N \ell,N ℓ,N则是为了方便我们进行表示而引入的记号, 并且他们在前面也出现过.
实际上这里就是变相生成了一组LWE问题的实例, 如果对这里不熟悉, 可以跟进我的Blog学习知识. 相关博文更新后会在这里补充地址.
这就是整个加密的过程, 其中 F l a t t e n \mathsf{Flatten} Flatten操作是为了保证 C C C是一个较小的矩阵, 我们知道 v \mathbf v v是一个 P o w e r o f 2 \mathsf{Powerof2} Powerof2向量, 那么
C v = ( μ ⋅ I N + B i t D e c o m p ( R ⋅ A ) ) v = μ ⋅ I N ⋅ v + R ⋅ A ⋅ s = μ ⋅ v + R ⋅ e C\mathbf v=(\mu\cdot I_N+\mathsf{BitDecomp}(R\cdot A))\mathbf v = \mu\cdot I_N\cdot \mathbf v + R\cdot A\cdot \mathbf s = \mu\cdot \mathbf v+R\cdot \mathbf e Cv=(μ⋅IN+BitDecomp(R⋅A))v=μ⋅IN⋅v+R⋅A⋅s=μ⋅v+R⋅e
R ⋅ e R\cdot \mathbf e R⋅e也是一个小噪声, 因此密文符合我们的要求.
实际上这里的解密过程就是比较 C v C\mathbf v Cv与 v \mathbf v v的值. 而为了使得解密出错的概率最低, 所以选择 v i v_i vi较大的一项, 这样使得错误最多可以积累到 q / 4 q/4 q/4而解密不出错.
接下来我们看一下进行 L L L层同态运算后, 噪声的增长. 我们知道, 两个噪声为 E E E的密文行一次加法运算, 噪声增长到 2 E 2E 2E. (这里 E = max i ∈ [ N ] e E=\max_{i\in [N]}\mathbf e E=maxi∈[N]e, 表示解密中的噪声项), 而两个噪声为 E E E的密文乘法结果的的噪声项为 μ 2 e 1 + C 1 e 2 \mu_2\mathbf e_1+C_1\mathbf e_2 μ2e1+C1e2, 最多为 ( N + 1 ) B 2 (N+1)B^2 (N+1)B2. 如果初始噪声为 E E E的密文进行 L L L层运算, 则噪声最多增长为 ( N + 1 ) L B 2 L (N+1)^LB^{2^L} (N+1)LB2L, 由这一点可以看出, 我们最多可以进行对数次数的同态运算. 但是对数次的运算已经足够用于解密运算, 因此我们可以基于Circular Security假设, 使用Bootstrapping技术实现全同态.
Craig Gentry是构造出第一个全同态加密方案的人, 可以说是同态加密方案的鼻祖. 现在的大多数同态加密方案都是在Gentry最初的方案的基础上改造而来的. ↩︎
Craig Gentry, Amit Sahai and Brent Waters. Homomorphic Encryption from Learning with Errors: Conceptually-Simpler, Asymptotically-Faster, Atribute-Based. Annual Cryptology Conference. Springer, Berlin, Heidelberg, 2013. ↩︎
实际上这里 v \mathbf v v并不是最终方案中的密钥 ↩︎
所有的向量都是列向量, 即 a = ( a 1 , ⋯   , a n ) = [ a 1 , ⋯   , a n ] T \mathbf a=(a_1,\cdots,a_n)=[a_1,\cdots,a_n]^T a=(a1,⋯,an)=[a1,⋯,an]T ↩︎
如果没有标明底数, log \log log的底数都是2. ↩︎
Daniele Micciancio and Chris Peikert. Trapdoors for lattices: Simpler, tighter, faster, smaller. In EUROCRYPT, pages 700-718, 2012.— ↩︎