2021SC@SDUSC PALISADE开源库(三)CKKS代码分析(三)高级代码步骤介绍
2021SC@SDUSC目录介绍大体步骤1. 启用TIC-TOC定时测量2. 定义要用到的函数以及方法3.“EXACTRESCALE”和“APPROXRESCALE”4.HYBRID切换技术5.缩放操作6. 手动重新调节演示介绍在这一篇博客中,我们主要是介绍了利用PALISADE的主要API来进行CKKS的同态加密解密以及实现的的大体步骤以及部分代码,如果想要看完整代码和运行过程及结果的同学,请查
2021SC@SDUSC
目录
3.“EXACTRESCALE”和“APPROXRESCALE”
介绍
在这一篇博客中,我们主要是介绍了利用PALISADE的主要API来进行CKKS的同态加密解密以及实现的的大体步骤以及部分代码,如果想要看完整代码和运行过程及结果的同学,请查看的我的下一篇博客来进行具体的操作。
大体步骤
1. 启用TIC-TOC定时测量
调用PROFILE来进行定时测量
#define PROFILE
#include "palisade.h"
using namespace lbcrypto;
2. 定义要用到的函数以及方法
void AutomaticRescaleDemo(RescalingTechnique rsTech);
void ManualRescaleDemo(RescalingTechnique rsTech);
void HybridKeySwitchingDemo1();
void HybridKeySwitchingDemo2();
void FastRotationsDemo1();
void FastRotationsDemo2();
3.“EXACTRESCALE”和“APPROXRESCALE”
我们的CKKS实现包括两个变体,分别称为“EXACTRESCALE”和“APPROXRESCALE”。从1.10版本开始,我们添加了APPROXAUTO变体,它的工作方式与APPROXRESCALE相同,但也可以自动缩放。
在我们开始之前,我们需要介绍一下规模操作,这是CKKS的核心。当我们将两个分别加密数字m1*D和m2*D的密文c1和c2相乘时,我们得到的结果看起来像m1*m2*D^2。因为这个数字的比例因子是D^2,我们说结果的深度是2。很明显,深度为2的密文不能加到深度为1的密文中,因为它们的缩放因子是不同的。重缩放取深度为2的密文,通过一个看起来很像除以D=2^p的操作使其深度为1。
出于效率的原因,我们的CKKS实现在RNS空间中工作,这意味着我们避免处理大数字,只处理本地整数。一个复杂的问题是我们只能通过除以某些质数来缩放而不是D=2^p。
有两种方法可以解决这个问题。第一种是选择尽可能接近2^p的质数,并假设比例因子保持不变。这不可避免地会导致一些近似误差,这就是为什么我们将其称为APPROXRESCALE变体。处理这个问题的第二种方法是跟踪比例因子是如何变化的,并尝试根据它进行调整。这就是CKKS的EXACTRESCALE变种。这样做的代价是EXACTRESCALE计算通常会稍微慢一些(根据我们的经验,根据计算的复杂性,速度会减慢5-35%),因为需要对值进行调整。
我们设计了EXACTRESCALE,所以它隐藏了追踪密文深度的所有细微差别,并不得不调用缩放操作。因此,EXACTRESCALE更适合那些不想深入了解底层加密和数学的细节,或者想要快速构建一个原型的用户。相反,APPROXRESCALE更适合于经过专家优化的生产应用程序。
本演示的前两部分通过使用EXACTRESCALE和APPROXRESCALE实现相同的计算,即函数f(x) = x^18 + x^9 + 1,介绍了这两种变体。
AutomaticRescaleDemo(EXACTRESCALE);
AutomaticRescaleDemo(APPROXAUTO);
ManualRescaleDemo(APPROXRESCALE);
4.HYBRID切换技术
我们的CKKS实现支持三种不同的密钥交换算法,即BV、GHS和HYBRID。BV对应于一种也被称为数字分解的技术(包括RNS和基于线性化窗口的技术)。GHS对应密文模加倍,HYBRID结合了BV和GHS的特性。关于不同的密钥开关技术的更多细节,请参考scheme/ckks/ckks.h中的KeySwitchBVGen、KeySwitchGHSGen和keyyswitchhybridgen文档。
在大多数情况下,HYBRID将是最合适和有效的键切换技术,这就是为什么我们将本演示的第三和第四部分用于混合键切换。
HybridKeySwitchingDemo1();
HybridKeySwitchingDemo2();
这个演示的最后部分展示了我们对一种叫做提升的优化技术的实现。其思想很简单——当我们想对同一密文执行多次不同的旋转时,我们可以一次计算旋转算法的一部分,然后多次重用它。
FastRotationsDemo1();
FastRotationsDemo2();
5.缩放操作
EXACTRESCALE是CKKS的一个变体,它有两个主要特性:1 -它在每次乘法之前自动执行缩放。这样做是为了让用户更容易编写FHE计算,而不必担心密文的深度或缩放。2 -它跟踪所有密文的精确比例因子。这意味着EXACTRESCALE中的计算将比APPROXRESCALE中的计算更精确。请记住,这种差异只有在处理大的乘法深度计算时才会变得明显;这是因为较大的乘法深度意味着我们需要找到更多足够接近D=2^p的质数,而随着乘法深度的增加,这变得越来越难。
if (rsTech == EXACTRESCALE) {
std::cout << "\n\n\n ===== ExactRescaleDemo ============= " << std::endl;
} else {
std::cout << "\n\n\n ===== ApproxAutoDemo ============= " << std::endl;
}
uint32_t multDepth = 5;
uint32_t scaleFactorBits = 50;
uint32_t batchSize = 8;
SecurityLevel securityLevel = HEStd_128_classic;
uint32_t ringDimension = 0;
CryptoContext<DCRTPoly> cc =
CryptoContextFactory<DCRTPoly>::genCryptoContextCKKS(
multDepth, scaleFactorBits, batchSize, securityLevel, ringDimension,
rsTech);
std::cout << "CKKS scheme is using ring dimension " << cc->GetRingDimension()
<< std::endl
<< std::endl;
cc->Enable(ENCRYPTION);
cc->Enable(SHE);
cc->Enable(LEVELEDSHE);
auto keys = cc->KeyGen();
cc->EvalMultKeyGen(keys.secretKey);
进行输入
vector<double> x = {1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7};
Plaintext ptxt = cc->MakeCKKSPackedPlaintext(x);
std::cout << "Input x: " << ptxt << std::endl;
auto c = cc->Encrypt(keys.publicKey, ptxt);
计算 f(x) = x^18 + x^9 + 1
auto c2 = cc->EvalMult(c, c); // x^2
auto c4 = cc->EvalMult(c2, c2); // x^4
auto c8 = cc->EvalMult(c4, c4); // x^8
auto c16 = cc->EvalMult(c8, c8); // x^16
auto c9 = cc->EvalMult(c8, c); // x^9
auto c18 = cc->EvalMult(c16, c2); // x^18
auto cRes = cc->EvalAdd(cc->EvalAdd(c18, c9), 1.0); // Final result
Plaintext result;
std::cout.precision(8);
cc->Decrypt(keys.secretKey, cRes, &result);
result->SetLength(batchSize);
std::cout << "x^18 + x^9 + 1 = " << result << std::endl;
6. 手动重新调节演示
std::cout << "\n\n\n ===== ApproxRescaleDemo ============= " << std::endl;
uint32_t multDepth = 5;
uint32_t scaleFactorBits = 50;
uint32_t batchSize = 8;
SecurityLevel securityLevel = HEStd_128_classic;
uint32_t ringDimension = 0;
CryptoContext<DCRTPoly> cc =
CryptoContextFactory<DCRTPoly>::genCryptoContextCKKS(
multDepth, scaleFactorBits, batchSize, securityLevel, ringDimension,
rsTech);
std::cout << "CKKS scheme is using ring dimension " << cc->GetRingDimension()
<< std::endl
<< std::endl;
cc->Enable(ENCRYPTION);
cc->Enable(SHE);
cc->Enable(LEVELEDSHE);
auto keys = cc->KeyGen();
cc->EvalMultKeyGen(keys.secretKey);
进行输入
vector<double> x = {1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7};
Plaintext ptxt = cc->MakeCKKSPackedPlaintext(x);
std::cout << "Input x: " << ptxt << std::endl;
auto c = cc->Encrypt(keys.publicKey, ptxt);
计算 f(x) = x^18 + x^9 + 1
// x^2
auto c2_depth2 = cc->EvalMult(c, c);
auto c2_depth1 = cc->Rescale(c2_depth2);
// x^4
auto c4_depth2 = cc->EvalMult(c2_depth1, c2_depth1);
auto c4_depth1 = cc->Rescale(c4_depth2);
// x^8
auto c8_depth2 = cc->EvalMult(c4_depth1, c4_depth1);
auto c8_depth1 = cc->Rescale(c8_depth2);
// x^16
auto c16_depth2 = cc->EvalMult(c8_depth1, c8_depth1);
auto c16_depth1 = cc->Rescale(c16_depth2);
// x^9
auto c9_depth2 = cc->EvalMult(c8_depth1, c);
// x^18
auto c18_depth2 = cc->EvalMult(c16_depth1, c2_depth1);
// 最终结果
auto cRes_depth2 = cc->EvalAdd(cc->EvalAdd(c18_depth2, c9_depth2), 1.0);
auto cRes_depth1 = cc->Rescale(cRes_depth2);
Plaintext result;
std::cout.precision(8);
cc->Decrypt(keys.secretKey, cRes_depth1, &result);
result->SetLength(batchSize);
std::cout << "x^18 + x^9 + 1 = " << result << std::endl;
更多推荐
所有评论(0)