基于近似计算的同态加密方案CKKS17----Encoding和Decoding

        本文主要是针对CKKS17以及OpenMined教程的学习心得。

        CKKS17方案中,加密前以及解密后需要进行Encode和Decode操作对明文编码和对解密后数据解码,大概过程如下图。

        论文中给的Encode(Ecd)和Decode(Dcd)的描述较为抽象,如下图,针对OpenMined中的代码来学习比较好理解。 

基础数学知识:

        欧拉公式:e^i^x=cos x+isin x

        本原单位根:M=8时:\Phi_M(X) = X^4 + 1\omega = e^{\frac{2 i \pi}{8}} = e^{\frac{i \pi}{4}}

        范德蒙矩阵:

        编码的思想:用本原单位根\omega_i构造范德蒙矩阵V,n*n维,欲编码明文为b,1*n维,则可以计算出一组1*n维的数p,满足pV=b,计算出的p就相当于一个多项式P(x)的系数,这样对不同的多项式系数进行运算就相当于对p所对应的b进行运算。这一编码过程我们称之为\sigma^-^1

        解码的思想:解码就比较简单,直接将\omega_i带入P(x)计算就会得到对应的明文值。

        例子:

        这里来看CKKS17论文中举的例子。这里T中的元素\zeta就相当于上面叙述过程中的\omega_i。此时构造范德蒙矩阵:\textbf{V}=\begin{bmatrix} (\zeta_8)^0 &(\zeta_8)^1 &(\zeta_8)^2 &(\zeta_8)^3 \\ (\zeta_8^3)^0 &(\zeta_8^3)^1 &(\zeta_8^3)^2 &(\zeta_8^3)^3 \end{bmatrix}。根据欧拉公式:e^i^x=cos x+isin x

和本原单位根在M=8时:\omega = e^{\frac{2 i \pi}{8}} = e^{\frac{i \pi}{4}},可以将上述范德蒙矩阵转换为复数形式进行计算。注意论文中提及的\zeta_8=exp(-2i\pi/8)\omega = e^{\frac{2 i \pi}{8}} = e^{\frac{i \pi}{4}}有符号上的差别,此处论文中和OpenMined中表述有差异。

        此时想要对z=(3+4i,2-i)进行编码。根据前面论述的:pV=b,即在pV=z中计算p。于是就可以得到p的结果为\frac{1}{4}(10,4\sqrt{2},10,2\sqrt{2}),所以可以得到多项式P(x)=\frac{1}{4}(10+4\sqrt{2}X+10X^2+2\sqrt{2}X^3),即完成了由复数向量向多项式的编码过程。

        原文中又乘了一个缩放因子64。解码过程只需要将\zeta_8\zeta_8^3带入P(x)中计算结果即可。

import numpy as np
import numpy as np

# First we set the parameters
M = 8
N = M //2

# We set xi, which will be used in our computations
xi = np.exp(2 * np.pi * 1j / M)
xi
(0.7071067811865476+0.7071067811865475j)

from numpy.polynomial import Polynomial

class CKKSEncoder:
    """Basic CKKS encoder to encode complex vectors into polynomials."""
    
    def __init__(self, M: int):
        """Initialization of the encoder for M a power of 2. 
        
        xi, which is an M-th root of unity will, be used as a basis for our computations.
        """
        self.xi = np.exp(2 * np.pi * 1j / M)
        self.M = M
        
    @staticmethod
    def vandermonde(xi: np.complex128, M: int) -> np.array:
        """Computes the Vandermonde matrix from a m-th root of unity."""
        
        N = M //2
        matrix = []
        # We will generate each row of the matrix
        for i in range(N):
            # For each row we select a different root
            root = xi ** (2 * i + 1)
            row = []

            # Then we store its powers
            for j in range(N):
                row.append(root ** j)
            matrix.append(row)
        return matrix
    
    def sigma_inverse(self, b: np.array) -> Polynomial:
        """Encodes the vector b in a polynomial using an M-th root of unity."""

        # First we create the Vandermonde matrix
        A = CKKSEncoder.vandermonde(self.xi, M)

        # Then we solve the system
        coeffs = np.linalg.solve(A, b)

        # Finally we output the polynomial
        p = Polynomial(coeffs)
        return p

    def sigma(self, p: Polynomial) -> np.array:
        """Decodes a polynomial by applying it to the M-th roots of unity."""

        outputs = []
        N = self.M //2

        # We simply apply the polynomial on the roots
        for i in range(N):
            root = self.xi ** (2 * i + 1)
            output = p(root)
            outputs.append(output)
        return np.array(outputs)


        上述代码中定义了生成范德蒙矩阵以及编码解码过程。

# First we set the parameters
M = 8
N = M //2

# We set xi, which will be used in our computations
xi = np.exp(2 * np.pi * 1j / M)
xi//(0.7071067811865476+0.7071067811865475j)

        可以看到xi就是(\frac{\sqrt{2}}{2},\frac{\sqrt{2}}{2}i)

M=8
b=np.array([1,2,3,4])
print("b:",b)
encoder=CKKSEncoder(M)


p=encoder.sigma_inverse(b)
print("p:",p)

b_r=encoder.sigma(p)
print("b_r:",b_r)

m1=np.array([1,2,3,4])
m2=np.array([1,-2,3,-4])

p1=encoder.sigma_inverse(m1)
p2=encoder.sigma_inverse(m2)

p_add=p1+p2
p_sub=p1-p2

poly_modulo=Polynomial([1,0,0,0,1])
p_mult=p1*p2%poly_modulo

m_add=encoder.sigma(p_add)
m_sub=encoder.sigma(p_sub)
m_mult=encoder.sigma(p_mult)

print(m_add)
print(m_sub)
print(m_mult)

        加减乘都可以正确运算,证明编码解码的正确性。注意乘法的实现,需要对X^n+1进行取模。

        此处有一个问题:运行m1的编码后多项式和OpenMined中给出的结果不同,但编码运算后加减乘都可以正确运算。

        此时编码是映射到了\mathbb{C}[X]/(X^N + 1)上,而实际是需要映射到\mathbb{Z}[X]/(X^N + 1)上,还需要\pi运算。\pi运算可以理解为转换基并规范化。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值