二 2021SC@SDUSC PALISADE开源库CKKS讲解系列(二)完整

@SDUSC
目录
介绍
CKKS编码和解码
编码: -> m(X)
解码:
相关代码执行(重要)
将输入的实数进行共轭处理
将万德蒙矩阵通过数组呈现出来
检查元素是否被编码为整数多项式
编码器和解码器相关代码
使用尺度参数Δ来实现固定的精度水平
完整的代码 + 执行(想看代码直接跳)
介绍
在上一篇开源库(二)CKKS讲解系列(一)普通编码和解码中 , 我们了解到 , 要实现CKKS加密方法和对加密复数向量的计算 , 我们必须构建一个编码器和一个解码器 , 将我们的复数向量转化为多项式 。
这个编码器——解码器步骤是必要的 , 因为加密、解密和其他机制也同样适用于多项式 。因此 , 有必要有一种方法将我们的实数值向量转化为多项式 。
在本文中 , 我们将探讨如何实现原始论文forof中使用的编码器和解码器 , 这将是我们从头开始实现 CKKS 的第一步 。
CKKS编码和解码
编码: -> m(X)
是一个n/2维的复向量 。我们在拿到一个复向量∈C^(n/2)之后 , 对他取一下共轭并且将原向量和共轭拼接在一起 , 得到增广的'∈C^n 。
举个例子 , ?我们拿到了一个复向量(3 +4j, 2 - 1j) 。按照上面的做法 , 我们增广为:
(3 + 4j, 2 - 1j, 3 - 4j, 2 + 1j)
考虑复数域内多项式 X^n +1 , 它有n个复数根ξi , 记这些复数根组成的向量为ξ , 并且前n/2个根和后n/2个根也是共轭的 。
下面 , 我们求一个整数系数的插值多项式m ( X )  , 使得m ( ξ ) ≈ Δ×'i 。即把 X^n + 1 = 0的根作为自变量丢到 m里面去 , 使得输出的值是的对应分量 。
由于共轭性质存在 , 插值出来的 m 的系数都是实数 。但是 , CKKS最后要对整数进行操作 , 因此在这里我们引入放大因子 Δ  , 将的数值放大之后再进行取整 。这样的话 , 可以尽可能保留小数的位数 , 提高加密的精度 。显然 , 如果直接对 m 系数取整 , 误差会比较大 。
m就是对消息编码的结果 。
对编码结果做存储时 , 我们只需要存储 m 的系数即可 。
解码:
把上述步骤倒过来就行了 。我们已知了 m  , 接下来把ξ 带入就完事了 。
最后别忘了除以Δ 就行 。
相关代码执行(重要)
现在我们终于知道了CKKS的编码和解码是如何工作的 , 下面我们来实现代码吧!
将输入的实数进行共轭处理
import numpy as np# 我们先设置一下参数M = 8class CKKSEncoder:""" 基本CKKS编码器将编码变为多项式 。"""def __init__(self, M: int):"""初始化编码器M的一个2的幂 。""""""xi , 是单位的第m次根 , 将作为我们计算的基础 。"""self.xi = np.exp(2 *np.pi * 1j / M)self.M = Mdef pi(self, z: np.array) -> np.array:"""将H的向量投影到C ^ {N / 2}中"""N = self.M // 4return z[:N]def pi_inverse(self, z: np.array) -> np.array:"""将向量C ^ {N / 2}展开复共轭 。"""z_conjugate = z[::-1]z_conjugate = [np.conjugate(x) for x in z_conjugate]return np.concatenate([z, z_conjugate])encoder = CKKSEncoder(M)# 现在我们可以用添加的方法初始化编码器encoder = CKKSEncoder(M)z = np.array([0, 1])p = np.array([3 +4j, 2 - 1j])print(encoder.pi_inverse(z))print(encoder.pi_inverse(p))
将万德蒙矩阵通过数组呈现出来
@staticmethoddef vandermonde(xi: np.complex128, M: int) -> np.array:"""从单位的m次根计算万德蒙矩阵 。"""N = M // 2matrix = []# 我们将生成矩阵的每一行for i in range(N):# 每一行我们选择一个不同的根root = xi ** (2 * i + 1)row = []# 然后我们储存它的权值for j in range(N):row.append(root ** j)matrix.append(row)return matrixdef create_sigma_R_basis(self):self.sigma_R_basis = np.array(self.vandermonde(self.xi, self.M)).Tprint(encoder.sigma_R_basis)