2021SC@SDUSC

目录

介绍

大体步骤

1. 启用TIC-TOC定时测量

2. 定义要用到的函数以及方法

3.“EXACTRESCALE”和“APPROXRESCALE”

4.HYBRID切换技术

5.缩放操作

6. 手动重新调节演示


介绍

         在这一篇博客中,我们主要是介绍了利用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;

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐