2021SC@SDUSC
目录
介绍
这篇文章我将从CKKS的源码进行入手,进一步理解CKKS的内部加密解密以及简单的加减乘等操作。毕竟是我第一次大规模的看别人的开源代码,有什么分析不对的地方希望大家指正,一起加油,一起进步!!!
源码分析
生成公钥
在我之前博客中 PALISADE开源库(二)CKKS讲解系列(三)加密和解密 大体介绍了加密解密以及简单的加法,如果不是很清楚大体过程的同学可以再去回顾一下,以便于了解。
生成组成公钥的要素 “ a ”
Element a(dug, elementParams, Format::EVALUATION);
生成秘钥 “ s ”
Element s;
给秘钥s进行赋值
不使用预先计算池中的随机多项式,分两步完成。支持离散高斯分布(RLWE),三元均匀分布(优化)和稀疏分布(sparse)情况。
switch (cryptoParams->GetMode()) {
case RLWE:
s = Element(dgg, elementParams, Format::COEFFICIENT);
break;
case OPTIMIZED:
s = Element(tug, elementParams, Format::COEFFICIENT);
break;
case SPARSE:
s = Element(tug, elementParams, Format::COEFFICIENT, 64);
break;
default:
break;
}
s.SetFormat(Format::EVALUATION);
生成并设置公钥
// privateKey->MakePublicKey(a, publicKey);
Element e(dgg, elementParams, Format::COEFFICIENT);
e.SetFormat(Format::EVALUATION);
//公钥b的生成
Element b = e - a * s;
调用上述方法给kp赋值并返回结果
kp.secretKey->SetPrivateElement(std::move(s));
kp.publicKey->SetPublicElementAtIndex(0, std::move(b));
kp.publicKey->SetPublicElementAtIndex(1, std::move(a));
// 给kp的是三个参数进行赋值 kp = (b, a)=(- a.s + e, a)
return kp;
实现密文之间的加法
主函数调用下面的方法
template <class Element>
Ciphertext<Element> LPAlgorithmSHECKKS<Element>::EvalAddCore(
ConstCiphertext<Element> ciphertext1,
ConstCiphertext<Element> ciphertext2) const {
Ciphertext<Element> result = ciphertext1->Clone();
//EvalAddCoreInPlace方法下面进行了定义
EvalAddCoreInPlace(result, ciphertext2);
return result;
}
EvalAddCoreInPlace 方法的定义
1)给出两个要进行计算的密文
void LPAlgorithmSHECKKS<Element>::EvalAddCoreInPlace(
Ciphertext<Element> &ciphertext1,
ConstCiphertext<Element> ciphertext2)
2)判断两个密文的深度是否相等,如果不相等,返回报错语句
if (ciphertext1->GetDepth() != ciphertext2->GetDepth()) {
PALISADE_THROW(config_error, "Depths of two ciphertexts do not match.");
}
3)判断两个密文的级别,如果第一个密文的级别小于第二个密文的级别,返回报错语句
if (ciphertext1->GetLevel() < ciphertext2->GetLevel()) {
PALISADE_THROW(config_error,
"EvalAddCoreInPlace cannot add ciphertexts with ciphertext1 "
"level less than ciphertext2 level.");
}
4)将两个密文分别拆分到两个容器内,以便进行操作
std::vector<Element> &cv1 = ciphertext1->GetElements();
const std::vector<Element> &cv2 = ciphertext2->GetElements();
5)分别计算两个密文容器长度大小,并记录长度小的数量
size_t c1Size = cv1.size();
size_t c2Size = cv2.size();
size_t cSmallSize = std::min(c1Size, c2Size);
6)将两个密文容器中长度小的范围内的数据进行相加操作
for (size_t i = 0; i < cSmallSize; i++) {
cv1[i] += cv2[i];
}
7)对长度大的密文容器中剩余的数据进行操作
如果第一个密文容器的长度大于第二个密文容器的长度的话,我们可以知道,cv1[i] += cv2[i];这样的话,不需要进行任何操作,cv1剩余的部分不需要进行操作就可以了。 但是,如果第一个密文容器的长度小于于第二个密文容器的长度的话,我们就要将第一个密文容器进行扩充到第二个密文容器的大小,然后将第二个密文容器内剩余的部分复制到第一个密文容器的空充补分就可以了。
if (c1Size < c2Size) {
cv1.reserve(c2Size);
for (size_t i = c1Size; i < c2Size; i++) {
cv1.emplace_back(cv2[i]);
}
}
实现密文之间的减法
1)给出两个要进行计算的密文
Ciphertext<Element> LPAlgorithmSHECKKS<Element>::EvalSubCore(
ConstCiphertext<Element> ciphertext1,
ConstCiphertext<Element> ciphertext2)
2)判断两个密文的深度是否相等,如果不相等,返回报错语句
if (ciphertext1->GetDepth() != ciphertext2->GetDepth()) {
PALISADE_THROW(config_error,
"LPAlgorithmSHECKKS<Element>::EvalSubCore - Depths of two "
"ciphertexts do not match.");
}
3)判断两个密文的级别是否相等,如果不相等,返回报错语句
if (ciphertext1->GetLevel() != ciphertext2->GetLevel()) {
PALISADE_THROW(config_error,
"EvalSubCore cannot sub ciphertexts with different number "
"of CRT components.");
}
4)设置一个计算结果的空容器
Ciphertext<Element> result = ciphertext1->CloneEmpty();
5)将两个密文分别拆分到两个容器内,以便进行操作
const std::vector<Element> &cv1 = ciphertext1->GetElements();
const std::vector<Element> &cv2 = ciphertext2->GetElements();
6)判断两个密文容器的大小,并记录密文容器大的长度和密文容器小的长度
size_t c1Size = cv1.size();
size_t c2Size = cv2.size();
size_t cSmallSize, cLargeSize;
if (c1Size < c2Size) {
cSmallSize = c1Size;
cLargeSize = c2Size;
} else {
cSmallSize = c2Size;
cLargeSize = c1Size;
}
7)设置一个减法分段计算的密文空间
std::vector<Element> cvSub;
8)将两个密文容器内共有长度的数据进行相减操作
for (size_t i = 0; i < cSmallSize; i++) {
cvSub.push_back(std::move(cv1[i] - cv2[i]));
}
9)将长度大的密文容器内剩余的数据进行操作
for (size_t i = cSmallSize; i < cLargeSize; i++) {
//被减数的长度小于减数的长度,将减数剩余部分取相反数添加到减法分段的密文空间
if (c1Size < c2Size)
cvSub.push_back(std::move(cv2[i].Negate()));
//被减数的长度大于减数的长度,将被减数剩余部分直接添加到减法分段的密文空间
else
cvSub.push_back(cv1[i]);
}
10)返回相减的计算结果
result->SetElements(std::move(cvSub));
result->SetDepth(ciphertext1->GetDepth());
result->SetScalingFactor(ciphertext1->GetScalingFactor());
result->SetLevel(ciphertext1->GetLevel());
实现密文之间的乘法
1)给出两个要进行计算的密文
Ciphertext<Element> LPAlgorithmSHECKKS<Element>::EvalMultCore(
ConstCiphertext<Element> ciphertext1,
ConstCiphertext<Element> ciphertext2)
2)判断两个密文的数据是否准确,如果不准确,返回报错语句
if (ciphertext1->GetElements()[0].GetFormat() == Format::COEFFICIENT ||
ciphertext2->GetElements()[0].GetFormat() == Format::COEFFICIENT) {
PALISADE_THROW(not_available_error,
"EvalMult cannot multiply in COEFFICIENT domain.");
}
3)判断两个密文的级别是否相等,如果不相等,返回报错语句
if (ciphertext1->GetLevel() != ciphertext2->GetLevel()) {
PALISADE_THROW(config_error,
"EvalMultCore cannot multiply ciphertexts with different "
"number of CRT components.");
}
4)设置一个计算结果的空容器
Ciphertext<Element> result = ciphertext1->CloneEmpty();
5)将两个密文分别拆分到两个容器内,以便进行操作
std::vector<Element> cv1 = ciphertext1->GetElements();
const std::vector<Element> &cv2 = ciphertext2->GetElements();
6)设置一个乘法分段计算的密文容器以及其长度
size_t cResultSize = cv1.size() + cv2.size() - 1;
std::vector<Element> cvMult(cResultSize);
7)进行相关的乘法操作(两种情况)
if (cv1.size() == 2 && cv2.size() == 2) {
// cvMult[0] = cv1[0] * cv2[0];
// cvMult[1] = (cv1[0] *= cv2[1]) + (cv2[0] * cv1[1]);
// cvMult[2] = (cv1[1] *= cv2[1]);
cvMult[2] = (cv1[1] * cv2[1]);
cvMult[1] = (cv1[1] *= cv2[0]);
cvMult[0] = (cv2[0] * cv1[0]);
cvMult[1] += (cv1[0] *= cv2[1]);
} else {
bool isFirstAdd[cResultSize];
std::fill_n(isFirstAdd, cResultSize, true);
for (size_t i = 0; i < cv1.size(); i++) {
for (size_t j = 0; j < cv2.size(); j++) {
if (isFirstAdd[i + j] == true) {
cvMult[i + j] = cv1[i] * cv2[j];
isFirstAdd[i + j] = false;
} else {
cvMult[i + j] += cv1[i] * cv2[j];
}
}
}
}
8)返回密文相乘的结果
result->SetElements(std::move(cvMult));
result->SetDepth(ciphertext1->GetDepth() + ciphertext2->GetDepth());
result->SetScalingFactor(ciphertext1->GetScalingFactor() *
ciphertext2->GetScalingFactor());
result->SetLevel(ciphertext1->GetLevel());
总结
这篇文章只是简单介绍了加密以及密文与密文之间的加减乘,并没有深入展开扩展加减乘等一系列操作,下一篇文章将展开进行扩展源码介绍,这篇文章就到此为止吧。