2021SC@SDUSC
密文的乘法同态:
由于密文的减法同态运算与加法同态运算类似,我们就不重复分析了,重点分析密文的乘法同态核心。
函数的申明,返回一个密文对象,输入两个密文对象作为同态操作数
template <class Element>
// 返回一个密文对象,输入两个密文对象作为同态操作数
Ciphertext<Element>
LPAlgorithmSHEBGVrns<Element>::EvalMultCore(
ConstCiphertext<Element> ciphertext1,
ConstCiphertext<Element> ciphertext2) const {
接着通过两个if语句限定乘法同态的适用范围:
// 乘法同态操作的适用范围
if (ciphertext1->GetElements()[0].GetFormat() == Format::COEFFICIENT ||
ciphertext2->GetElements()[0].GetFormat() == Format::COEFFICIENT) {
PALISADE_THROW(not_available_error,
"EvalMult cannot multiply in COEFFICIENT domain.");
}
// 两个密文的CRT等级不同也无法进行乘法同态
if (ciphertext1->GetLevel() != ciphertext2->GetLevel()) {
PALISADE_THROW(config_error,
"EvalMultCore cannot multiply ciphertexts with different "
"number of CRT components.");
}
声明一个密文对象用于存放乘法同态的结果密文向量:
//声明一个密文对象用于存放乘法同态的结果向量
Ciphertext<Element> result = ciphertext1->CloneEmpty();
提取函数参数中的密文对象的密文向量
//提取函数参数中的密文对象的蜜文向量
const std::vector<Element> &cv1 = ciphertext1->GetElements();
const std::vector<Element> &cv2 = ciphertext2->GetElements();
乘法结果的维数计算:计算乘法同态的过程是多项式乘法,多项式的每一项都要与乘法同态的另一个多项式的所有向相乘,再合并相同的维数的项,记两个密文多项式向量分别为c1、c2,所以结果的维数 = c1维数+c2维数-1(0维占据一个维数),因为c1的第0维与c2第2维的结果要与c1的第1维与c2第1维的结果储存在cResult的第2维,所以结果向量最小维数为0,最大的维数为c1.max+c2.max-1
size_t cResultSize = cv1.size() + cv2.size() - 1;
我们声明一个密文向量 存放乘法同态的运算结果
std::vector<Element> cvMult(cResultSize);
利用一个结果维数大小的bool数组来说明结果向量数组中某个维数是否第一次赋值
// 标记结果向量数组的某个维数是否是第一次赋值
bool isFirstAdd[cResultSize];
// 填充默认值True
std::fill_n(isFirstAdd, cResultSize, true);
同多项式乘法的过程,按照cv1与cv2的维数遍历,设当前计算的维数为n=i+j,如果cvMult[n]
第一次赋值(isFirstAdd[n]=true
),则直接赋值cvMult[i + j] = cv1[i] * cv2[j];
,其他情况进行+=运算。
// 按照cv1与cv2的维数遍历
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];
}
}
}
最后我们将运算结果保存在result
密文对象中,返回它,函数结束。
// 将结果向量保存在结果密文对象中
result->SetElements(std::move(cvMult));
result->SetDepth(ciphertext1->GetDepth() + ciphertext2->GetDepth());
result->SetLevel(ciphertext1->GetLevel());
// 返回密文对象
return result;
}
完整代码如下:
template <class Element>
// 返回一个密文对象,输入两个密文对象作为同态操作数
Ciphertext<Element>
LPAlgorithmSHEBGVrns<Element>::EvalMultCore(
ConstCiphertext<Element> ciphertext1,
ConstCiphertext<Element> ciphertext2) const {
// 乘法同态操作的适用范围
if (ciphertext1->GetElements()[0].GetFormat() == Format::COEFFICIENT ||
ciphertext2->GetElements()[0].GetFormat() == Format::COEFFICIENT) {
PALISADE_THROW(not_available_error,
"EvalMult cannot multiply in COEFFICIENT domain.");
}
// 两个密文的CRT等级不同也无法进行乘法同态
if (ciphertext1->GetLevel() != ciphertext2->GetLevel()) {
PALISADE_THROW(config_error,
"EvalMultCore cannot multiply ciphertexts with different "
"number of CRT components.");
}
//声明一个密文对象用于存放乘法同态的结果向量
Ciphertext<Element> result = ciphertext1->CloneEmpty();
//提取函数参数中的密文对象的蜜文向量
const std::vector<Element> &cv1 = ciphertext1->GetElements();
const std::vector<Element> &cv2 = ciphertext2->GetElements();
// 计算乘法同态的过程是多项式乘法,多项式的每一项都要与另一个多项式的所有向相乘,在合并相同的维数,所以结果的维数 = c1维数+c2维数-1
// 因为c1的第0维与c2第2维的结果要与c1的第1维与c2第1维的结果储存在cResult的第2维,所以结果向量最小维数为0,最大的维数为c1.max+c2.max-1
size_t cResultSize = cv1.size() + cv2.size() - 1;
//声明一个密文向量 存放乘法同态的运算结果
std::vector<Element> cvMult(cResultSize);
// 标记结果向量数组的某个维数是否是第一次赋值
bool isFirstAdd[cResultSize];
// 填充默认值True
std::fill_n(isFirstAdd, cResultSize, true);
// 按照cv1与cv2的维数遍历
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];
}
}
}
// 将结果向量保存在结果密文对象中
result->SetElements(std::move(cvMult));
result->SetDepth(ciphertext1->GetDepth() + ciphertext2->GetDepth());
result->SetLevel(ciphertext1->GetLevel());
// 返回密文对象
return result;
}