CKKS Part1:普通编码和解码
这篇文章,翻译于:【CKKS EXPLAINED: PART 1, VANILLA ENCODING AND DECODING】
主要介绍为CKKS中编码/解码做铺垫,讲一些基础知识
介绍#
同态加密是一个很有前途的领域,它允许对密文进行计算。下面这篇优秀的文章《什么是同态加密》对同态加密是什么以及这一研究领域的利害关系进行了广泛的解释。
在本系列文章中,我们将深入研究Cheon-Kim-Song(CKKS)方案,该方案首次在论文《Homomorphic Encryption for Arithmetic of Approximate Numbers》中讨论。CKKS允许我们对复数向量(也就是实数)进行计算。我们的想法是,我们将用Python实现CKKS,然后通过使用这些加密原语,我们可以探索如何执行复杂的操作,如线性回归、神经网络等。
上图提供了CKKS的主要流程。我们可以看到,消息m是一个向量,我们希望对其执行某些计算,它首先被编码为明文多项式
CKKS使用多项式,因为与向量计算相比,它们在安全性和效率之间提供了良好的折衷。【也就是使用RLWE和LWE之间区别,RLWE更加安全和高效】
一旦消息m被加密为c(一对多项式),CKKS就提供了几个可以对其执行的操作,例如加法、乘法和旋转。
如果我们用f表示函数,f是同态运算【加法和乘法】的组合,那么用私钥去解密 c'=f(c),然后解码,我们将得到m=f(m)。
实现同态加密方案的核心思想是在编码、解码、加密和解密上具有同态属性,这样,对密文的操作将被正确地解密和解码,并提供输出,就像直接对明文进行操作一样。
因此,在本文中,我们将看到如何实现编码和解码,在后面的文章中,我们将继续实现加密和解密,以获得同态加密方案。
预备知识#
建议掌握线性代数和环理论的基本知识,以便更好地理解CKKS是如何实现的。您可以通过以下链接了解这些主题:
- 线性代数导论为线性代数提供了良好的基础。
- 环理论(数学113)是学习环理论的好资源。
具体到本文中,我们将依赖以下概念:
- 分圆多项式(Cyclotomic polynomials)是一种具有优良性质的多项式,当用作多项式模时,它具有高效的计算。
- 用于编码和解码的标准嵌入(canonical embedding)。它们具有很好的同构性质,即向量和多项式之间的一对一同态对应。
- 范德蒙矩阵(Vandermonde matrices)是一类特殊的矩阵,我们将用它来求标准嵌入的逆。
如果你想运行该项目的代码,你可以在这里找到它。
CKKS编码#
CKKS利用整型多项式环的丰富结构实现其明文和密文空间。尽管如此,数据更多地以向量的形式出现,而不是以多项式的形式出现。
因此,我们需要将输入的复数向量
用N表示多项式模的次数,其中N是二的次幂。把
为了理解如何将向量编码为多项式,以及对多项式执行计算是如何反映在向量上的,我们将首先用一个普通的示例进行实验,我们将一个复数向量
然后介绍CKKS编码:将一个复数向量
普通编码#
这里我们将简单介绍将一个复数向量
为此,我们使用标准嵌入
想法很简单,将多项式
所以为了解码多项式
麻烦的是如何把向量
进一步研究这个问题,我们最终得到了以下系统:
这可以看作是一个线性方程:
所以我们有
举例#
强力推荐使用:https://colab.research.google.com/drive/1C2WlzTh-28GUxobvIQK6Nj5GdfunAlH2?usp=sharing
现在让我们来看一个例子,以便更好地理解。
假定
我们的目标是对以下向量进行编码:[1,2,3,4]和[−1,−2,−3,−4] ;对它们进行解码;对它们编码后的多项式进行加法和乘法;然后对其计算结果进行解码。
正如我们所见,为了解码多项式,我们只需要根据M次单位根的幂来计算它。我们这里选择
一旦我们有了
实现#
1、现在我们使用Python实现普通的编码和解码:
import numpy as np
# First we set the parameters
M = 8
N = M //2
# We set xi, which will be used in our computations(计算M次单位根)
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(计算M次单位根).
"""
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.(根据M次单位根计算范德蒙矩阵)"""
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(只需将M次单位根的次幂代入多项式即可)
for i in range(N):
root = self.xi ** (2 * i + 1)
output = p(root)
outputs.append(output)
return np.array(outputs)
2、让我们先对一个实数向量进行编码:
# First we initialize our encoder(新建一个对象)
encoder = CKKSEncoder(M)
b = np.array([1, 2, 3, 4])
b
array([1, 2, 3, 4])
现在对该向量进行编码:
p = encoder.sigma_inverse(b)
p
输出:
3、现在让我们看看如何从多项式中提取我们最初得到的向量(解码):
b_reconstructed = encoder.sigma(p)
b_reconstructed
输出:
我们可以看到解码值和初始向量非常接近。
np.linalg.norm(b_reconstructed - b)//误差范数
输出:
如前所述,不是随机选择的
4、我们现在可以开始对几个向量进行编码,看看如何对它们执行同态运算并对其进行解码。
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_add
输出:
正如预期的那样,我们看到p1+p2正确解码为[2,0,6,0]。
encoder.sigma(p_add)
输出:
5、因为在进行乘法运算时,我们可能会得到阶数大于N的项,我们需要使用
要执行乘法,我们首先需要定义我们将使用的多项式模。
poly_modulo = Polynomial([1,0,0,0,1])
poly_modulo
输出:
现在我们可以进行乘法运算了。
p_mult = p1 * p2 % poly_modulo
p
输出:
6、最后,如果我们解码它,我们可以看到我们得到了预期的结果。
encoder.sigma(p_mult)
输出:
因此,我们可以看到,我们的简单编码和解码正常,因为它具有同态特性,并且是向量和多项式之间的一一映射。
虽然这是一个很大的进步,但我们实际上撒谎了,因为如果你之前注意到,当我们编码时
所以我希望你们喜欢这篇关于将复数编码成多项式进行同态加密的小介绍。我们将在下一篇文章中看到如何实现CKKS中使用的实际编码和解码,敬请期待!
作者:Hang Shao
出处:https://www.cnblogs.com/pam-sh/p/15856470.html
版权:本作品采用「知识共享」许可协议进行许可。
声明:欢迎交流! 原文链接 ,如有问题,可邮件(mir_soh@163.com)咨询.
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· PPT革命!DeepSeek+Kimi=N小时工作5分钟完成?
· What?废柴, 还在本地部署DeepSeek吗?Are you kidding?
· DeepSeek企业级部署实战指南:从服务器选型到Dify私有化落地
· 程序员转型AI:行业分析
2021-01-31 GitHub 图片无法加载(持续更新)
2020-01-31 python3基础