Lattigo入门学习3

Lattigo之浮点数加解密

先简单回顾,CKKS(Cheon-Kim-Kim-Song)加密方案是一种在同态加密领域中广泛应用的方案,特别是在处理实数和复数上的计算时表现出了优异的性能。CKKS方案允许对编码后的近似实数或复数进行加密,然后进行同态加密操作(如加法和乘法),最后能够解密出一个近似的结果。这种加密方案特别适合用于需要处理大量实数数据的机器学习和数据分析场景。

CKKS方案的核心步骤是通过一系列复杂的代数和数论操作来实现的。下面是这个方案的关键步骤和相关公式的一个概览。请注意,实际的CKKS实现涉及更复杂的数学,并且这里的描述只是为了提供一个概念框架。

CKKS方案

1. 参数设置和密钥生成

首先,选择一个安全参数 λ λ λ,然后根据 λ λ λ 选择多项式的度数 N N N(通常是 2 2 2的幂)以及一系列模数 ( q 1 q_1 q1, q 2 q_2 q2, ..., q L q_L qL ) 来构建模数链。接下来,生成密钥对:

  • 私钥 sk: 随机选择一个小项多项式 ( s ∈ R ) ( s \in R ) (s∈R)。
  • 公钥 pk: 计算 ( ( p 0 , p 1 ) ) ( (p_0, p_1) ) ((p0,p1)) 其中 ( p 0 , p 1 ∈ R q ) ( p_0, p_1 \in R_q ) (p0,p1∈Rq) 并且 ( p 0 = − a s + e + Δ m ) ( p_0 = -as + e + \Delta m ) (p0=−as+e+Δm) (其中 ( a ) ( a ) (a) 是随机选择的, ( e ) ( e ) (e) 是一个小项误差多项式,( Δ \Delta Δ ) 是用来调整比例的大整数,以便于编码实数)。
2. 加密过程

加密一个复数向量 ( m ⃗ ) ( \vec{m} ) (m ) 的步骤如下:

  • 编码:首先,将复数向量 $( \vec{m} ) $编码到一个多项式 ( m ( x ) ) ( m(x) ) (m(x)) 中。

  • 加密:然后计算密文 $c = (c_0, c_1) $ 其中:

    [ c 0 = p 0 ⋅ r + e 0 + Δ ⋅ m ( x ) m o d    q ] [ c_0 = p_0 \cdot r + e_0 + \Delta \cdot m(x) \mod q ] [c0=p0⋅r+e0+Δ⋅m(x)modq]
    [ c 1 = p 1 ⋅ r + e 1 m o d    q ] [ c_1 = p_1 \cdot r + e_1 \mod q ] [c1=p1⋅r+e1modq]

    这里的 ( r r r ) 是随机选择的,( e 0 e_0 e0 ) 和 ($ e_1$ ) 是小项误差多项式。

3. 同态运算

CKKS方案支持同态加法和乘法:

  • 同态加法:给定两个密文 ( $c^{(1)} = (c_0^{(1)}, c_1^{(1)}) $) 和 ( $c^{(2)} = (c_0^{(2)}, c_1^{(2)}) $),它们的和为:

    [ c ( 1 + 2 ) = ( c 0 ( 1 ) + c 0 ( 2 ) , c 1 ( 1 ) + c 1 ( 2 ) ) ] [ c^{(1+2)} = (c_0^{(1)} + c_0^{(2)}, c_1^{(1)} + c_1^{(2)}) ] [c(1+2)=(c0(1)+c0(2),c1(1)+c1(2))]

  • 同态乘法:对于乘法,通常需要执行relinearization和rescaling步骤来保持密文的可管理大小。这里省略具体步骤的描述。

4. 解密过程

解密一个密文 ( c = ( c 0 , c 1 ) c = (c_0, c_1) c=(c0,c1) ),使用私钥 ($ s $) 来计算:

[ m ( x ) = ( c 0 + c 1 ⋅ s ) m o d    q m o d    x N + 1 ] [ m(x) = \left( c_0 + c_1 \cdot s \right) \mod q \mod x^N + 1 ] [m(x)=(c0+c1⋅s)modqmodxN+1]

然后从多项式 ( m(x) ) 中解码出原始的复数向量。

5. 解码

解码过程涉及到从多项式 ( m ( x ) m(x) m(x) ) 中恢复出编码前的向量 ( m ⃗ \vec{m} m )。这通常包括舍去多项式系数的缩放因子 ( Δ \Delta Δ ) 以及将多项式的系数转换回复数。

CKKS方案的详细实现比上述描述要复杂得多,在这里我只做简要回顾,有兴趣的还是读原文Homomorphic Encryption for Arithmetic of Approximate Numbers (iacr.org)

CKKS加解密浮点数实例

接下来我们具体实现一个CKKS加密的例子,我们随机生成 X X X向量和 Y Y Y向量,我们对两个变量执行 ( X − Y ) 2 (X-Y)^2 (X−Y)2并打印输出最终结果。

  • 声明参数和钥匙

    go 复制代码
    package main
    
    import (
    	"fmt"
    	"math/rand"
    
    	"github.com/tuneinsight/lattigo/v5/core/rlwe"
    	"github.com/tuneinsight/lattigo/v5/he/hefloat"
    )
    
    func main() {
    	//paramter
    	var err error
    	var params hefloat.Parameters
    
    	if params, err = hefloat.NewParametersFromLiteral(
    		hefloat.ParametersLiteral{
    			LogN:            14,                                    // log2(ring degree)
    			LogQ:            []int{55, 45, 45, 45, 45, 45, 45, 45}, // log2(primes Q) (ciphertext modulus)
    			LogP:            []int{61},                             // log2(primes P) (auxiliary modulus)
    			LogDefaultScale: 45,                                    // log2(scale)
    		}); err != nil {
    		panic(err)
    	}
    
    	// Key Generator
    	keygen := rlwe.NewKeyGenerator(params)
    	sk := keygen.GenSecretKeyNew()
    	encoder := hefloat.NewEncoder(params)
    	encryptor := rlwe.NewEncryptor(params, sk)
    	decryptor := rlwe.NewDecryptor(params, sk)
    
    	rlk := keygen.GenRelinearizationKeyNew(sk)
    	evk := rlwe.NewMemEvaluationKeySet(rlk)
    	evaluator := hefloat.NewEvaluator(params, evk)
  • 构造数据并加密

    go 复制代码
    // generate data
    	x := make([]float64, params.MaxSlots())
    	y := make([]float64, params.MaxSlots())
    
    	r1 := rand.New(rand.NewSource(0))
    	for i := range x {
    		x[i] = r1.Float64()
    	}
    
    	r2 := rand.New(rand.NewSource(1))
    	for i := range y {
    		y[i] = r2.Float64()
    	}
    
    	// encoder and encryptor
    	plaintext_x := hefloat.NewPlaintext(params, params.MaxLevel())
    	plaintext_y := hefloat.NewPlaintext(params, params.MaxLevel())
    	var ct_x *rlwe.Ciphertext
    	var ct_y *rlwe.Ciphertext
    
    	if err = encoder.Encode(x, plaintext_x); err != nil {
    		panic(err)
    	}
    	if err = encoder.Encode(y, plaintext_y); err != nil {
    		panic(err)
    	}
    
    	if ct_x, err = encryptor.EncryptNew(plaintext_x); err != nil {
    		panic(err)
    	}
    	if ct_y, err = encryptor.EncryptNew(plaintext_y); err != nil {
    		panic(err)
    	}
  • 进行密文计算

    go 复制代码
    	//(x-y)
    	var ct_sub *rlwe.Ciphertext
    	if ct_sub, err = evaluator.SubNew(ct_x, ct_y); err != nil {
    		panic(err)
    	}
    
    	//(x-y)^2
    	var ct_square *rlwe.Ciphertext
    	if ct_square, err = evaluator.MulRelinNew(ct_sub, ct_sub); err != nil {
    		panic(err)
    	}
  • 显示输出

    go 复制代码
    	//print x and y data
    	fmt.Printf("X: ")
    	for i := 0; i < 4; i++ {
    		fmt.Printf("%f ", x[i])
    	}
    	fmt.Println()
    
    	fmt.Printf("Y: ")
    	for i := 0; i < 4; i++ {
    		fmt.Printf("%f ", y[i])
    	}
    	fmt.Println()
    
    	//print x-y
    	pt_sub := decryptor.DecryptNew(ct_sub)
    	have := make([]float64, params.MaxSlots())
    	if err = encoder.Decode(pt_sub, have); err != nil {
    		panic(err)
    	}
    	fmt.Printf("X-Y: ")
    	for i := 0; i < 4; i++ {
    		fmt.Printf("%f ", have[i])
    	}
    	fmt.Println()
    
    	//print (x-y)^2
    	pt_square := decryptor.DecryptNew(ct_square)
    	if err = encoder.Decode(pt_square, have); err != nil {
    		panic(err)
    	}
    	fmt.Printf("(X-Y)^2: ")
    	for i := 0; i < 4; i++ {
    		fmt.Printf("%f ", have[i])
    	}
    	fmt.Println()
    }

通过这个例子,我们展现了一些基本的用法,当然基础的用法还包括一些操作比如evaluator.Add(),但其操作都比较类似,就不赘述了。

相关推荐
数据小爬虫@20 分钟前
利用Python爬虫获取淘宝店铺详情
开发语言·爬虫·python
Hacker_Oldv27 分钟前
网络安全的学习路线
学习·安全·web安全
蒟蒻的贤31 分钟前
vue学习11.21
javascript·vue.js·学习
高 朗31 分钟前
【GO基础学习】基础语法(2)切片slice
开发语言·学习·golang·slice
寒笙LED1 小时前
C++详细笔记(六)string库
开发语言·c++·笔记
码上有前1 小时前
解析后端框架学习:从单体应用到微服务架构的进阶之路
学习·微服务·架构
IT书架1 小时前
golang面试题
开发语言·后端·golang
初遇你时动了情1 小时前
uniapp 城市选择插件
开发语言·javascript·uni-app
岳不谢1 小时前
VPN技术-VPN简介学习笔记
网络·笔记·学习·华为
海害嗨2 小时前
阿里巴巴官方「SpringCloudAlibaba全彩学习手册」限时开源!
学习·开源