同态加密:CKKS方案简介及一个python实现:TENSEAL(不定期更新)
Posted Nu1Lpo1hT3r
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了同态加密:CKKS方案简介及一个python实现:TENSEAL(不定期更新)相关的知识,希望对你有一定的参考价值。
部分资料来自于HEAAN作者的个人主页:https://yongsoosong.github.io/files/slides/intro_to_CKKS.pdf
0x01 同态加密的CKKS方案简介
CKKS是2017年提出的同态加密方案。它支持浮点向量在密文空间的加减乘运算并保持同态,但是只支持有限次乘法的运算。
同态加密极简介绍
举个例子:
实数域里有加法和乘法。多项式域里面有多项式加法和多项式乘法。我们把实数域中的数或者向量映射到多项式域(加密),在多项式域里做一些多项式加法和多项式乘法的运算之后,再把多项式映射回实数域(解密),得到的结果和实数域里做对应的加法和乘法的结果相同或者相似。这种在私密领域(例如多项式域)做确保结果一致性的计算技术就叫同态加密。
LWE问题的极简介绍
格(lattice)
在线性空间中给定一组线性无关的向量,其整数线性组合生成的集合称为格。
关于格的详细介绍,不妨移步这里。
LWE问题
我们有了若干的
(
a
,
b
)
(a, b)
(a,b)对,其中
a
a
a为整数向量,
b
b
b为整数(均在mod Q意义下)。现在需要找一个线性函数
f
f
f,使得
f
(
a
)
≈
b
f(a) \\approx b
f(a)≈b。由Risez表示定理,总是存在一个和a形状相同的
s
s
s,使得
f
(
a
)
=
(
a
,
s
)
f(a) = (a, s)
f(a)=(a,s),其中
(
a
,
s
)
(a, s)
(a,s)是
a
a
a和
s
s
s的内积。在CKKS中,这里的线性函数就是
a
a
a和私钥
s
s
s做内积,私钥
s
s
s也是整数向量(mod Q),即可以理解为求解线性方程组:
(
a
i
,
s
)
=
b
i
(a_i, s) = b_i
(ai,s)=bi
但是,在LWE(learning with error)问题中,我们加入了一些误差,此即:
(
a
i
,
s
)
+
e
i
=
b
i
(a_i, s) + e_i = b_i
(ai,s)+ei=bi
其中,内积
(
∗
,
s
)
( * ,s)
(∗,s)就表示待定的
f
(
∗
)
f(*)
f(∗)(因为f是线性的)。
e
e
e为整数,是引入的误差。
如果没有误差的话,高斯消去法可以把 s s s解出来,但是误差的引入和对 s s s中元素整数性的要求就使得解会特别病态甚至搞不出来符合要求的解。
上面所说的LWE问题是search-LWE问题,即已知
a
,
b
a, b
a,b寻找
s
s
s。
还有一种Decision-LWE问题,说的是判断
b
b
b到底是随机生成的整数向量还是由
(
a
,
s
)
+
e
(a, s) + e
(a,s)+e生成的东西。
RLWE问题
和LWE问题类似,只不过这里的
a
,
b
,
s
a, b, s
a,b,s 都是整数多项式,而且对应地LWE里的内积换成了多项式的乘法。可以证明,这个问题的求解也是困难的。
CKKS操作步骤
这里就直接贴图了,会附上一些文字说明帮助理解。
上图是CKKS的一个大概流程。先对消息(向量)进行编码,然后再加密,在密文空间进行一些运算后再解密,最后解码成运算后的消息(向量)。
注意,这里的编码指的是将复数向量映射成为多项式,是为了方便下面进一步的加密,
上图是编解码的方法。
编码:Message -> m(X)
M e s s a g e Message Message是一个 n 2 \\fracn2 2n 维的复向量。在拿到一个复向量 M e s s a g e ∈ C n 2 Message \\in C^\\fracn2 Message∈C2n之后,对它取一下共轭并且将原向量和共轭拼接在一起,得到増广的 M e s s a g e ′ ∈ C n Message' \\in C^n Message′∈Cn。
比如,我们拿到了一个复向量 ( 1 + 4 i , 5 − 2 i ) (1 + 4i, 5 - 2i) (1+4i,5−2i)。按照上面所说的做法,我们将它増广为:
( 1 + 4 i , 5 − 2 i , 1 − 4 i , 5 + 2 i ) (1 + 4i, 5 - 2i, 1-4i, 5+2i) (1+4i,5−2i,1−4i,5+2i)
考虑复数域内多项式 X n + 1 X^n+1 Xn+1,它有 n n n个复根 ξ i \\xi_i ξi,记这些复根组成的向量为 ξ \\xi ξ ,并且前 n 2 \\fracn2 2n个根和后 n 2 \\fracn2 2n个根也是共轭的。
下面,我们求一个整数系数的插值多项式 m ( X ) m(X) m(X)(用牛顿插值、拉格朗日插值、快速傅里叶变换啥的都可以),使得 m ( ξ ) ≈ Δ × M e s s a g e i ′ m(\\xi) \\approx \\Delta \\times Message'_i m(ξ)≈Δ×Messagei′。即把 X n + 1 = 0 X^n + 1 = 0 Xn+1=0 的复数根作为自变量丢到 m m m 里面去,使得输出的值是 M e s s a g e ′ Message' Message′的对应分量。
由于共轭性质,插值出来的 m m m 的系数都是实数。但是,CKKS最后要对整数进行操作,因此需要对多项式系数进行取整。如果直接对 m m m 系数取整,误差会比较大。因此在这里我们引入放大因子 Δ \\Delta Δ ,将Message的数值放大,得到 m = m ⋅ Δ m = m · \\Delta m=m⋅Δ之后再进行取整。这样的话,可以尽可能保留小数的位数,提高加密的精度。但是引入了放大这样一个操作之后,多项式系数就不可避免地变大了很多。如果再做很多乘法,那就不可避免地会出现溢出的情形。它的应对方法可以参考下面的重缩放部分。
m m m 即为对消息编码的结果。
对编码结果做存储时,我们只需要存储 m m m 的系数即可。
按理说,这里的n需要是2的幂,但是由于这里我们只涉及编码解码操作,所以没有特别地提及这个事情,因为这里n/2只要是整数的话,不影响后面加解密的运算。只有在旋转和bootstrap下需要使用到n是2的幂这个条件,因为此时的分圆多项式的形状比较好,是 X n + 1 X^n+1 Xn+1的形式。
解码:Message <- m(X)
把上述步骤倒过来就行了。我们已知了 m m m,接下来把 ξ \\xi ξ 带进去就完事了。
最后别忘了除以 Δ \\Delta Δ就行。
加密:m(X) -> (c0(X), c1(X))
这里,我们取私钥
(
1
,
s
)
(1, s)
(1,s),公钥
(
b
=
−
a
⋅
s
+
e
,
a
)
(b = -a·s + e, a)
(b=−a⋅s+e,a),其中
s
s
s 和
a
a
a 是向量,
e
e
e是一个随机数,
b
b
b 是一个数。(这里就由RLWE问题确保了一件事:仅使用公钥的话很难解出私钥)
则密文
(
c
0
,
c
1
)
=
r
(
b
,
a
)
+
(
m
+
e
1
,
e
2
)
=
(
r
b
+
m
+
e
1
,
r
a
+
e
2
)
(c_0, c_1) = r(b, a) + (m + e_1, e_2) = (rb + m + e_1, ra + e_2)
(c0,c1)=r(b,a)+(m+e1,e2)=(rb+m+e1,ra+e2),其中
r
r
r是随机整数,
e
1
,
e
2
e_1, e_2
e1,eBGV方案简介(同态加密)