HEAAN新版学习

本篇文章对最新版的HEAAN库进行研究,老版的介绍见 HEAAN库学习
主要参考:slide-HEAAN.pdf

HEAAN介绍#

HEAAN是一个支持在加密的复数数组之间进行操作的库,方案的安全性取决于logQlogN和高斯分布的标准差σ=3.2。如果使用 Martin’s LWE parameter estimator,你可以检测这个方案的安全性。

lwe-estimator,是一个Sage函数【Sage更多:参考】,用于测试求解LWE问题的运行时间
个人理解,求解LWE运行时间越长,越安全,所以推荐用此时的参数?后面单独花时间再研究这个,在这里我就理解成从这里这里选取更好的参数。

下面是难点之一编码,将一个复数向量编码成一整数多项式:

encode:(m1,...,ml)ClΔm(x)Z[X]/(XN+1)

密文是一对多项式(a(x),b(x))ZQ,例如:对于私钥是s(x)Z=Z[X]/(XN+1)ZQ=R/QR

b(x)=a(x)s(x)+Δm(x)+e(x)a(x)R[X]/(XN+1)

下面是主要函数
encode:输入mCl,输出一个多项式m(x)
decode:输入m(x),输出一个复数向量m
encrypt:输入m,编码,加密,返回密文(a(x),b(x))
decrypt:输入(a(x),b(x)),解密,解码,返回m
add:输入两个密文,返回密文m1+m2
square:输入一个密文,返回密文m+m
mult:输入两个密文,返回密文m1m2
rotate:输入一个密文,返回旋转后的密文

HEAAN使用#

预备知识#

首先需要确定缩放因子Δ和目标电路深度(乘法次数)L,这将会确定最大模数Q=ΔL。使用安全参数λ和LWE参数评估器(这里理解为lwe-estimator),我们将会选择密文多项式的维数(次数)N

Context context(logN, logQ);
用于编码和解密时计算复数,这个类包含encodedecode函数,这个类在老版本中出现。

ZZX mx = context.encode(mvec,slots,pBits);
返回编码结果m(x),即一个整数多项式;这里的pBitslog2Δ

密钥生成#

在HEAAN方案中,我们需要额外的公钥,即用于乘法运算的计算密钥,这是在RPQ2上的一对多项式,这里的P是一个特殊的模数,和Q有相同的比特位数,其安全性基于RLWE(2logQ,logN,σ)问题

SecretKey sk(logN, h);
生成私钥(一个稀疏多项式)s(x),该多项式的系数取自HWT(h)={1,0,1}分布,即多项式系数中有h个正整数。

Scheme scheme(sk, context);
生成下面两个公钥:

pkenc=(a(x),a(x)s(x)+e(x))ZPQ2

pkmult=(a(x),a(x)s(x)+Ps2(x)+e(x))ZPQ2

如果需要旋转功能的话,也需要生成一个公钥:
scheme.addConjKey(sk);
scheme.addLeftRotKey(sk,i);
scheme.addRightRotKey(sk.i);
为左旋转和右旋转生成对应的公钥

pkleftRot,i=(a(x),a(x)s(x)+Ps2(xk)e(x))ZPQ2

其中k=5ImodN,共轭情况下k=2N1,用作右旋转下k=5i,该公钥用于索引为i的明文数组的左旋转,如果运行scheme.addLeftRotKeysscheme.addRightRotKeys将会产生两个方向上旋转的公钥。

一直有一个疑惑,为什么要进行旋转?
因为明文都是向量(实数或复数),用旋转可以提升效率!
什么是旋转?
CKKS中的旋转大多就是进行对于矩阵的旋转,通俗一点讲就是,对于矩阵来说,旋转列可能就是将一列元素进行向左或者是向右进行平移。旋转行可能就是将矩阵的每两行进行对调,从而实现旋转的操作。旋转是不消耗任何的噪音预算的。

同态计算#

同态加法有多种版本,注意,我们也可以在明文和密文之间进行加法。

cipher3 = scheme.add(cipher1, cipher2);
scheme.addAndEqual(cipher1, cipher2);
cipher2 = scheme.addConst(cipher1, const);

这些算法相当快。对于常用参数,两个密文之间的相加只需要10毫秒到20毫秒。请注意,addAndEqual 将计算新结果直接赋值给输入的第一个密文,由于内存分配时间的原因,这会稍微快一点。

同态乘法有多种版本,注意,我们也可以在明文和密文之间进行乘法:

cipher2 = scheme.square(cipher1);
cipher2 = scheme.squareAndEqual(cipher1);
cipher3 = scheme.mult(cipher1, cipher2);
scheme.multAndEqual(cipher1, cipher2);
cipher2 = scheme.multByConst(cipher1, const);

那些算法除了multByConst都会使用计算密钥pkmult,这大约需要100毫秒到1000毫秒,这取决于缩放因子Δ和目标电路深度(乘法次数)L

重缩放#

密文(缩放因子为Δ)相乘后缩放因子变为Δ2,所以我们需要使用重缩放,其中pBitslog2Δ

cipher2 = scheme.reScaleBy(cipher1, pBits);
scheme.reScaleByAndEqual(cipher1, pBits);

缩放因子变为Δ,密文模数变为Q/Δ

同态旋转#

cipher2 = scheme.leftRotateBy(cipher1, i);
scheme.leftRotateByAndEqual(cipher1, i);
cipher2 = scheme.rightRotateBy(cipher1, i);
scheme.rightRotateByAndEqual(cipher1, i);

每一次旋转都需要使用对应的旋转公钥,如果没有,将自动 combine power of two shifting【没看太懂,是自动生成么?】

例子#

// Key Generation
Context context(logN, logQ);
SecretKey sk(logN);//私钥
Scheme scheme(sk, context);//公钥、计算密钥
scheme.addLeftRotKey(sk, 1);//左旋转密钥
// Encrypt
Ciphertext cipher1 = scheme.encrypt(mvec1, slots, pBits, logQ);
Ciphertext cipher2 = scheme.encrypt(mvec2, slots, pBits, logQ);
// Homomorphic Operations
Ciphertext addCipher = scheme.add(cipher1, cipher2);
Ciphertext multCipher = scheme.mult(cipher1, cipher2);//乘法
scheme.reScaleByAndEqual(multCipher, pBits);//重缩放
Ciphertext rotCipher = scheme.leftRotate(cipher1, 1);//将密文1向左旋转一位
// Decrypt
complex<double>* dvecAdd = scheme.decrypt(sk, addCipher);
complex<double>* dvecMult = scheme.decrypt(sk, multCipher);
complex<double>* dvecRot = scheme.decrypt(sk, rotCipher);

作者:Hang Shao

出处:https://www.cnblogs.com/pam-sh/p/15884427.html

版权:本作品采用「知识共享」许可协议进行许可。

声明:欢迎交流! 原文链接 ,如有问题,可邮件(mir_soh@163.com)咨询.

posted @   PamShao  阅读(1283)  评论(5编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· PPT革命!DeepSeek+Kimi=N小时工作5分钟完成?
· What?废柴, 还在本地部署DeepSeek吗?Are you kidding?
· DeepSeek企业级部署实战指南:从服务器选型到Dify私有化落地
· 程序员转型AI:行业分析
点击右上角即可分享
微信分享提示
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu