2021SC@SDUSC
照例先分析PALISADE库的特性,再讨论BVG方法。
PlainText
PALISADE
中使用明文(PlainText
)表示未加密的内容。它实际上是PALISADE中支持的每种可能的纯文本编码的基类:【1】
• PackedEncoding
• CKKSPackedEncoding
• CoefPackedEncoding
• StringEncoding
明文的用途:
-
创建明文
PlainText
是通过调用适当的CryptoContext
类的方法,方法的参数是未加密的信息 -
一旦创建,明文
PlainText
可以使用CryptoContext
的Encrypt
方法加密为密文Ciphertext
。 -
PlainText
还可以用作多个CryptoContext
同态操作的参数, -
当密文
Ciphertext
被解密时,解密方法创建一个新的Plaintext
来包含解密
明文有几个方法提供对明文中的信息的访问,在/core/include/encoding/plaintext.h中的319行:
virtual const std::string& GetStringValue() const {
PALISADE_THROW(type_error, "not a string");
}
virtual const vector<int64_t>& GetCoefPackedValue() const {
PALISADE_THROW(type_error, "not a packed coefficient vector");
}
virtual const vector<int64_t>& GetPackedValue() const {
PALISADE_THROW(type_error, "not a packed coefficient vector");
}
virtual const std::vector<std::complex<double>>& GetCKKSPackedValue() const {
PALISADE_THROW(type_error, "not a packed vector of complex numbers");
}
virtual const std::vector<double> GetRealPackedValue() const {
PALISADE_THROW(type_error, "not a packed vector of real numbers");
}
virtual void SetStringValue(const std::string&) {
PALISADE_THROW(type_error, "does not support a string");
}
virtual void SetIntVectorValue(const vector<int64_t>&) {
PALISADE_THROW(type_error, "does not support an int vector");
}
明文PlainText
类中对明文的编码类型(PlaintextEncodings
)、明文的元素类型都有定义:
enum PlaintextEncodings {
Unknown = 0,
CoefPacked,
Packed,
String,
CKKSPacked,
};
enum PtxtPolyType { IsPoly, IsDCRTPoly, IsNativePoly };
class PlaintextImpl {
protected:
//是否被编码
bool isEncoded;
//元素类型
PtxtPolyType typeFlag;
//编码参数
EncodingParams encodingParams;
}
Evaluation中的加法评估
当我们手上有密文时,我们可以对该密文进行加法或乘法,运算的对象可以是其他的密文或明文,这是全同态加密算法的关键。PALISADE中关于评估函数的内容在bgvrns.cpp
与bgvrns-impl.cpp
中都有涉及,但是bgvrns-imp.cpp
中的评估函数调用的是bgvrns.cpp
内的,BVGRNS只支持DCRTPoly
类的加密,自然评估函数也只支持DCRTPoly
类,以加法为例:
//Poly类型没有加密方法
template <>
void LPAlgorithmSHEBGVrns<Poly>::EvalAddInPlace(
Ciphertext<Poly>& ciphertext1,
ConstCiphertext<Poly> ciphertext2) const {
NOPOLY
}
//NativePoly类型没有加密方法
template <>
void LPAlgorithmSHEBGVrns<NativePoly>::EvalAddInPlace(
Ciphertext<NativePoly>& ciphertext1,
ConstCiphertext<NativePoly> ciphertext2) const {
NONATIVEPOLY
}
template <>
void LPAlgorithmSHEBGVrns<DCRTPoly>::EvalAddInPlace(
Ciphertext<DCRTPoly>& ciphertext1,
ConstCiphertext<DCRTPoly> ciphertext2) const {
auto ciphertext2_clone = ciphertext2->Clone();
AdjustLevelsEq(ciphertext1, ciphertext2_clone);
// 将两个密文作为参数执行EvalAddCoreInPlace方法
EvalAddCoreInPlace(ciphertext1, ciphertext2_clone);
}
template <>
Ciphertext<DCRTPoly> LPAlgorithmSHEBGVrns<DCRTPoly>::EvalAdd(
ConstCiphertext<DCRTPoly> ciphertext, ConstPlaintext plaintext) const {
auto inPair = AdjustLevels(ciphertext, plaintext);
// 执行一个明文与一个密文的评估函数
return EvalAddCore(*(inPair.first), inPair.second);
}
转回到bgvrns.cpp
,重点分析EvalAddCoreInPlace
与EvalAddCore
方法。先从简单的EvalAddCore
分析:
//返回一个密文,输入一个明文与一个密文
template <class Element>
Ciphertext<Element> LPAlgorithmSHEBGVrns<Element>::EvalAddCore(
ConstCiphertext<Element> ciphertext, Element ptxt) const {
//创建要返回的密文,赋初值为空
Ciphertext<Element> result = ciphertext->CloneEmpty();
//获取密文向量
const std::vector<Element> &cv = ciphertext->GetElements();
//设置明文的格式为Format::EVALUATION
ptxt.SetFormat(Format::EVALUATION);
std::vector<Element> cvAdd(cv);
//明文向量与密文向量相加
cvAdd[0] += ptxt;
//设置返回密文为相加的值
result->SetElements(std::move(cvAdd));
result->SetDepth(ciphertext->GetDepth());
result->SetLevel(ciphertext->GetLevel());
//返回加法同态的结果
return result;
}
当进行加法同态的元素是两个密文时,需要考虑密文的维数不同的印象,具体的EvalAddCoreInPlace
方法如下:
template <class Element>
void LPAlgorithmSHEBGVrns<Element>::EvalAddCoreInPlace(
Ciphertext<Element> &ciphertext1,
ConstCiphertext<Element> ciphertext2) const {
函数声明传入两个密文对象,同时与EvalAddCore
不同的是,该函数并不返回结果,而是将加法同态的运算结果赋给第一个密文(后面会涉及)。
if (ciphertext1->GetLevel() != ciphertext2->GetLevel()) {
PALISADE_THROW(config_error,
"EvalAddCore cannot add ciphertexts with different number "
"of CRT components.");
}
首先判断两个密文的Level,不同则报错
std::vector<Element> &cv1 = ciphertext1->GetElements();
const std::vector<Element> &cv2 = ciphertext2->GetElements();
取出两个密文的密文向量
size_t c1Size = cv1.size();
size_t c2Size = cv2.size();
size_t cSmallSize = std::min(c1Size, c2Size);
获取两个密文向量的维数与最小维数
for (size_t i = 0; i < cSmallSize; i++) {
cv1[i] += cv2[i];
}
if (c1Size < c2Size) {
cv1.reserve(c2Size);
for (size_t i = c1Size; i < c2Size; i++) {
cv1.emplace_back(cv2[i]);
}
}
将共有的维数范围内的向量值相加,if代码块的目的是保证cv1
密文向量是有最大的维数,如果不是则将cv2
多的部分填充给cv1
。
ciphertext1->SetDepth(
std::max(ciphertext1->GetDepth(), ciphertext2->GetDepth()));
最后设置Depth,完成了密文的加法同态,ciphertext1
密文保存了结果。
参考
【1】PALISADE Lattice Cryptography Library User Manual (v1.11.5)