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


【二2021SC@SDUSC PALISADE开源库CKKS讲解系列(二)完整】注意 , 这矩阵输出的时候 , 进行了转置
检查元素是否被编码为整数多项式
coordinates = [1,1,1,1]b = np.matmul(encoder.sigma_R_basis.T, coordinates)print(b)p = encoder.sigma_inverse(b)print(p)
编码器和解码器相关代码
def compute_basis_coordinates(self, z):"""计算向量相对于正交基的坐标 。"""output = np.array([np.real(np.vdot(z, b) / np.vdot(b, b)) for b in self.sigma_R_basis])return outputdef round_coordinates(coordinates):"""给出积分剩余部分"""coordinates = coordinates - np.floor(coordinates)return coordinatesdef coordinate_wise_random_rounding(coordinates):r = CKKSEncoder.round_coordinates(coordinates)f = np.array([np.random.choice([c, c - 1], 1, p=[1 - c, c]) for c in r]).reshape(-1)rounded_coordinates = coordinates - frounded_coordinates = [int(coeff) for coeff in rounded_coordinates]return rounded_coordinatesdef sigma_R_discretization(self, z):"""使用坐标随机四舍五入将矢量投影到坐标上 。"""coordinates = self.compute_basis_coordinates(z)rounded_coordinates = CKKSEncoder.coordinate_wise_random_rounding(coordinates)y = np.matmul(self.sigma_R_basis.T, rounded_coordinates)return y
使用尺度参数Δ来实现固定的精度水平
def encode(self, z: np.array) -> Polynomial:pi_z = self.pi_inverse(z)scaled_pi_z = self.scale * pi_zrounded_scale_pi_zi = self.sigma_R_discretization(scaled_pi_z)p = self.sigma_inverse(rounded_scale_pi_zi)# We round it afterwards due to numerical imprecisioncoef = np.round(np.real(p.coef)).astype(int)p = Polynomial(coef)return pdef decode(self, p: Polynomial) -> np.array:rescaled_p = p / self.scalez = self.sigma(rescaled_p)pi_z = self.pi(z)return pi_z
完整的代码 + 执行(想看代码直接跳)
import numpy as np# 我们先设置一下参数M = 8scale = 64from numpy.polynomial import Polynomialclass CKKSEncoder:""" 基本CKKS编码器将编码变为多项式 。"""def __init__(self, M:int, scale:float):"""初始化编码器M的一个2的幂 。""""""xi , 是单位的第m次根 , 将作为我们计算的基础 。"""self.xi = np.exp(2 *np.pi * 1j / M)self.M = Mself.create_sigma_R_basis()self.scale = scaledef 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])@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 sigma(self, p: Polynomial) -> np.array:"""通过将多项式应用于单位的m次根来解码多项式"""outputs = []N = self.M // 2# 我们只需要把多项式应用到根上for i in range(N):root = self.xi ** (2 * i + 1)output = p(root)outputs.append(output)return np.array(outputs)def sigma_inverse(self, b: np.array) -> Polynomial:"""用m次单位根将向量b编码成多项式 。"""# 首先我们先创建一个万德蒙矩阵A = CKKSEncoder.vandermonde(self.xi, M)# 然后我们解决这个方程coeffs = np.linalg.solve(A, b)# 最后我们输出这个多项式p = Polynomial(coeffs)return pdef create_sigma_R_basis(self):self.sigma_R_basis = np.array(self.vandermonde(self.xi, self.M)).Tdef compute_basis_coordinates(self, z):"""计算向量相对于正交基的坐标 。"""output = np.array([np.real(np.vdot(z, b) / np.vdot(b, b)) for b in self.sigma_R_basis])return outputdef round_coordinates(coordinates):"""给出积分剩余部分"""coordinates = coordinates - np.floor(coordinates)return coordinatesdef coordinate_wise_random_rounding(coordinates):r = CKKSEncoder.round_coordinates(coordinates)f = np.array([np.random.choice([c, c - 1], 1, p=[1 - c, c]) for c in r]).reshape(-1)rounded_coordinates = coordinates - frounded_coordinates = [int(coeff) for coeff in rounded_coordinates]return rounded_coordinatesdef sigma_R_discretization(self, z):"""使用坐标随机四舍五入将矢量投影到坐标上 。"""coordinates = self.compute_basis_coordinates(z)rounded_coordinates = CKKSEncoder.coordinate_wise_random_rounding(coordinates)y = np.matmul(self.sigma_R_basis.T, rounded_coordinates)return ydef encode(self, z: np.array) -> Polynomial:pi_z = self.pi_inverse(z)scaled_pi_z = self.scale * pi_zrounded_scale_pi_zi = self.sigma_R_discretization(scaled_pi_z)p = self.sigma_inverse(rounded_scale_pi_zi)# We round it afterwards due to numerical imprecisioncoef = np.round(np.real(p.coef)).astype(int)p = Polynomial(coef)return pdef decode(self, p: Polynomial) -> np.array:rescaled_p = p / self.scalez = self.sigma(rescaled_p)pi_z = self.pi(z)return pi_z# 现在我们可以用添加的方法初始化编码器encoder = CKKSEncoder(M, scale)z = np.array([3 +4j, 2 - 1j])print(z)p = encoder.encode(z)print(p)q = encoder.decode(p)print(q)