这篇文章,翻译于:【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是一个向量,我们希望对其执行某些计算,它首先被编码为明文多项式$p(X)$,然后使用公钥进行加密。

CKKS使用多项式,因为与向量计算相比,它们在安全性和效率之间提供了良好的折衷。【也就是使用RLWE和LWE之间区别,RLWE更加安全和高效】

一旦消息m被加密为c(一对多项式),CKKS就提供了几个可以对其执行的操作,例如加法、乘法和旋转。

如果我们用f表示函数,f是同态运算【加法和乘法】的组合,那么用私钥去解密 c'=f(c),然后解码,我们将得到m=f(m)。

实现同态加密方案的核心思想是在编码、解码、加密和解密上具有同态属性,这样,对密文的操作将被正确地解密和解码,并提供输出,就像直接对明文进行操作一样。

因此,在本文中,我们将看到如何实现编码和解码,在后面的文章中,我们将继续实现加密和解密,以获得同态加密方案。

预备知识

建议掌握线性代数和环理论的基本知识,以便更好地理解CKKS是如何实现的。您可以通过以下链接了解这些主题:

具体到本文中,我们将依赖以下概念:

如果你想运行该项目的代码,你可以在这里找到它。

CKKS编码

CKKS利用整型多项式环的丰富结构实现其明文和密文空间。尽管如此,数据更多地以向量的形式出现,而不是以多项式的形式出现。

因此,我们需要将输入的复数向量\(z\in \mbox{C}^{\frac{N}{2}}\)编码成一个多项式\(m\left( X \right)=\frac{Z\left[ X \right]}{X^{N}+1}\)。

用N表示多项式模的次数,其中N是二的次幂。把\(\Phi _{M}=X^{N}+1\)(其中M=2N)叫做M次分圆多项式。明文空间是多项式环\(R=\frac{Z\left[ X \right]}{X^{N}+1}\)。用\(\xi _{M}=e^{\frac{2i\pi }{M}}\)表示M次单位根

为了理解如何将向量编码为多项式,以及对多项式执行计算是如何反映在向量上的,我们将首先用一个普通的示例进行实验,我们将一个复数向量\(z\in \mbox{C}^N\)编码为一个复数多项式\(m\left( X \right)=\frac{C\left[ X \right]}{X^{N}+1}\),然后介绍CKKS编码:将一个复数向量\(z\in \mbox{C}^{N/2}\)编码为一个整数多项式\(m\left( X \right)=\frac{Z\left[ X \right]}{X^{N}+1}\)。

普通编码

这里我们将简单介绍将一个复数向量\(z\in \mbox{C}^N\)编码为一个复数多项式\(m\left( X \right)=\frac{C\left[ X \right]}{X^{N}+1}\)的情况。

为此,我们使用标准嵌入\(\sigma :\frac{\mbox{C}\left[ X \right]}{X^{N}+1}—>\mbox{C}^{N}\),对我们的向量进行解码和编码。

想法很简单,将多项式\(m(X)\)解码为一个向量\(z\) ,即用分圆多项式\(\Phi _{M}=X^{N}+1\)的根\(\xi ,\xi ^{3},...,\xi ^{2N-1}\)去计算该多项式。

所以为了解码多项式\(m(X)\),我们定义\(\sigma \left( m \right)=m\left( m\left( \xi \right),m\left( \xi ^{3} \right),...,m\left( \xi ^{2N-1} \right) \right)\),这里\(σ\)定义了一个同构,这意味着它是一个双射同态,因此任何向量都将唯一地编码到其相应的多项式中,反之亦然。【意思就是,只需把这些根带入多项式,就能得到对应的向量值】。

麻烦的是如何把向量\(z\in \mbox{C}^N\)编码成多项式\(m\left( X \right)=\frac{C\left[ X \right]}{X^{N}+1}\),这意味着要求\(σ^{-1}\),因此问题就是要找到一个多项式\(m\left( X \right)=\sum_{}^{}{\alpha _{i}X^{i}\in \frac{\mbox{C}\left[ X \right]}{\left( X^{N}+1 \right)}}\),给出一个向量\(z\in \mbox{C}^{N}\),使得\(\sigma \left( m \right)=m\left( m\left( \xi \right),m\left( \xi ^{3} \right),...,m\left( \xi ^{2N-1} \right) \right)=(z_1,...,z_N)\)。

进一步研究这个问题,我们最终得到了以下系统:\(\sum_{}^{}{\alpha _{j}\left( \zeta ^{2i-1} \right)^{j}=z_{i}},i=1,...,N\)。

这可以看作是一个线性方程:\(\Alpha \alpha =z\),其中A是\(\left( \zeta ^{2i-1} \right)_{i=1,...,N}\)的范德蒙矩阵,\(σ\)是多项式的系数,z是我们编码得到的向量。

所以我们有\(\alpha =\Alpha ^{-1}z\),\(\sigma ^{-1}\left( z \right)=\sum_{}^{}{\alpha _{i}X^{i}\in \frac{\mbox{C}\left[ X \right]}{X^{N}+1}}\)。

举例

现在让我们来看一个例子,以便更好地理解我们到目前为止讨论的内容。

假定\(M=8,N=\frac{M}{2}=4,\Phi _{M}\left( X \right)=X^{4}+1,\omega =e^{\frac{2i\pi }{8}}=e^{\frac{i\pi }{4}}\)

我们的目标是对以下向量进行编码:[1,2,3,4]和[−1,−2,−3,−4] ,对它们进行解码,对它们的多项式进行加法和乘法,然后对其进行解码。



正如我们所见,为了解码多项式,我们只需要根据M次单位根的幂来计算它。我们这里选择\(\xi _{M}=\omega =e^{\frac{i\pi \pi }{4}}\)。

一旦我们有了\(\xi\)和 \(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
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)

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

输出:\(x↦(2.5+4.440892098500626e^-16j)+((-4.996003610813204e^{-16}+0.7071067811865479j))x+((-3.4694469519536176e^{-16}+0.5000000000000003j))x^2+((-8.326672684688674e^{-16}+0.7071067811865472j))x^3\)

3、现在让我们看看如何从多项式中提取我们最初得到的向量:

b_reconstructed = encoder.sigma(p)
b_reconstructed

输出:\(array([1.-1.11022302e^{-16}j, 2.-4.71844785e^{-16}j, 3.+2.77555756e^{-17}j, 4.+2.22044605e^{-16}j])\)

我们可以看到重建值和初始向量非常接近。

np.linalg.norm(b_reconstructed - b)

输出:\(6.944442800358888e-16\)

如前所述,不是随机选择σ来编码和解码的,但它有很多很好的特性。其中,σ是同构的,因此多项式的加法和乘法将导致编码向量的系数的加法和乘法。

σ的同态性质是由于:\(X^{N}+1=0\; and\; \zeta ^{N}+1=0\)

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

输出:\(x↦(2.0000000000000004+1.1102230246251565e^{-16}j)+((-0.7071067811865477+0.707106781186547j))x+((2.1094237467877966e^{-15}-1.9999999999999996j))x^2+((0.7071067811865466+0.707106781186549j))x^3\)

正如预期的那样,我们看到p1+p2正确解码为[2,0,6,0]。

encoder.sigma(p_add)

输出:\(array([2.0000000e+00+3.25176795e-17j, 4.4408921e-16-4.44089210e-16j, 6.0000000e+00+1.11022302e-16j, 4.4408921e-16+3.33066907e-16j])\)

5、因为在进行乘法运算时,我们可能会得到阶数大于N的项,我们需要使用\(X^N+1\)进行模运算。

要执行乘法,我们首先需要定义我们将使用的多项式模。

poly_modulo = Polynomial([1,0,0,0,1])
poly_modulo

输出:\(x↦1.0+0.0x+0.0x^2+0.0x^3+1.0x^4\)

现在我们可以进行乘法运算了。

p_mult = p1 * p2 % poly_modulo

6、最后,如果我们解码它,我们可以看到我们得到了预期的结果。

encoder.sigma(p_mult)

输出:\(array([ 1.-8.67361738e-16j, -4.+6.86950496e-16j, 9.+6.86950496e-16j, -16.-9.08301212e-15j])\)

因此,我们可以看到,我们的简单编码和解码正常,因为它具有同态特性,并且是向量和多项式之间的一对一映射。

虽然这是一个很大的进步,但我们实际上撒谎了,因为如果你之前注意到,当我们编码时\(σ^{-1}\),多项式有复系数。因此,虽然编码和解码确实是同态的,而且是一对一的,但它们所涵盖的领域是相同的\(C^N→ℂ[X] /(X^N+1)\)。因为我们真的希望多项式属于\(ℤ[X] /(X^N+1)\)为了使用整数多项式环的所有属性,我们需要确保编码输出具有整数系数而不是复数系数的多项式。

举一个比较具体的例子:

所以我希望你们喜欢这篇关于将复数编码成多项式进行同态加密的小介绍。我们将在下一篇文章中看到如何实现CKKS中使用的实际编码和解码,敬请期待!

CKKS :Part1,普通编码/解码的更多相关文章

  1. SIMD编码/解码

    在看SEAL库和HElib库中经常在编码中碰到打包(batch)技术,另外还提到了SIMD编码技术,有点困惑,编码.打包.SIMD到底有什么关系? 编码 在CKKS方案中,因为明文空间在复数域上,简单 ...

  2. C# base 64图片编码解码

    使用WinForm实现了图片base64编码解码的 效果图: 示例base 64编码字符串: /9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKD ...

  3. java中文乱码解决之道(五)-----java是如何编码解码的

    在上篇博客中LZ阐述了java各个渠道转码的过程,阐述了java在运行过程中那些步骤在进行转码,在这些转码过程中如果一处出现问题就很有可能会产生乱码!下面LZ就讲述java在转码过程中是如何来进行编码 ...

  4. java中文乱码解决之道(六)-----javaWeb中的编码解码

    在上篇博客中LZ介绍了前面两种场景(IO.内存)中的java编码解码操作,其实在这两种场景中我们只需要在编码解码过程中设置正确的编码解码方式一般而言是不会出现乱码的.对于我们从事java开发的人而言, ...

  5. Unicode编码解码在线转换工具

    // Unicode编码解码在线转换工具 Unicode 是基于通用字符集(Universal Character Set)的标准来发展,并且同时也以书本的形式(The Unicode Standar ...

  6. .NET编码解码(HtmlEncode与HtmlEncode)

    编码代码: System.Web.HttpUtility.HtmlEncode("<a href=\"http://hovertree.com/\">何问起& ...

  7. sed处理url编码解码=== web日志的url处理

    URL 编码/解码方法(linux  shell实现),方法如下: 1.编码的两种方法: admin@~ 11:14:29>echo '手机' | tr -d '\n' | xxd -plain ...

  8. ASP.NET中Url编码解码

    今天遇到Url编码解码的问题,纠结了一天的时间,结果上网一查才发现太二了我们. 同事写的代码把url用HttpUtility.UrlEncode编码和解码了,本地测试没有问题,部署到服务器上就提示转码 ...

  9. C++ Base64 编码 解码

    C++实现 base64 字符串编码解码(GCC编译). /** * @brief C++ base64 编解码 * @author wid * @date 2013-20-25 * * @note ...

随机推荐

  1. 【LeetCode】500. Keyboard Row 解题报告(Java & Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 暴力解 字典 + set 日期 题目地址:https ...

  2. 【LeetCode】114. Flatten Binary Tree to Linked List 解题报告(Python & C++ & Java)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 先序遍历 递归 日期 题目地址:https://le ...

  3. 【LeetCode】304. Range Sum Query 2D - Immutable 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 预先求和 相似题目 参考资料 日期 题目地址:htt ...

  4. Robin Hood

    Robin Hood 题目链接 题意 给你n个人和他们的钱数,然后给你k天,每天可以从最高钱数的人那边取一块钱给最少钱数的人,问最后钱数最多的人和钱数最少的人相差多少: 思路 二分最钱数,能下降到的位 ...

  5. 【系统分析】《系统分析与设计方法》 Jeffrey L.Whitten 第1部分 系统开发环境 第3章 信息系统开发

    1.解释为什么对企业来说,拥有一个标准的系统开发过程很重要. 开发过程的成熟,使项目时间和费用减少,生产率和质量提高 2.如何关联系统生命周期和系统开发方法学? 系统生命周期包含系统开发阶段,其中使用 ...

  6. 【Java】质数判断

    static boolean isPrime(int n) { if(n<=1) { return false; } if(n==2||n==3) { return true; } if(n%6 ...

  7. 【Java例题】5.4 排序集合的使用

    4.排序集合的使用.使用TreeSet模拟一个一维整数数组.其中,一维整数数组元素由Random类随机产生.最后显示排序后的结果. package chapter6; import java.util ...

  8. Auto-Encoding Variational Bayes

    目录 主要内容 Encoder (损失part1) Decoder (损失part2) 伯努利分布 高斯分布 代码 Kingma D P, Welling M. Auto-Encoding Varia ...

  9. BUUCTF [极客大挑战 2019]Not Bad

    总的来说这是一个64位orw的题 开头先在主函数里分配了一个很大的空间 1 __int64 __fastcall main(int a1, char **a2, char **a3) 2 { 3 mm ...

  10. 编写Java程序,在维护英雄数据的业务过程中复用数据库操作封装类

    返回本章节 返回作业目录 需求说明: 继续完善英雄信息系统,将HeroAccess类中数据库连接相关代码独立出来,并将其封闭成数据库操作工具类DbConnection,便于管理和代码复用. 在Hero ...