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 ) (sR)
  • 公钥 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,p1Rq) 并且 ( 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=p0r+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=p1r+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+c1s)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 (XY)2并打印输出最终结果。

  • 声明参数和钥匙

    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)
    
    
  • 构造数据并加密

    // 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)
    	}
    
  • 进行密文计算

    	//(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)
    	}
    
  • 显示输出

    	//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(),但其操作都比较类似,就不赘述了。

  • 11
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值