2021SC@SDUSC
本节继续分析BGV的解密过程,解密过程的具体实现主要在bgvrns-impl.cpp
内。
1 PALISADE中的CryptoContext
PALISADE的核心的类是CryptoContext
类,该类是提供所有 PALISADE 加密功能的类。PALISADE 实现中使用的所有对象均由CryptoContext
类创建。【1】
PALISADE对象的所有操作必须在相同的属于CryptoContext
类的对象上进行,加密明文(Plaintext
)生成密文(Ciphertext
)的过程如下:
上一节分析的加密过程就是属于这个流程。每个的加密过程的CryptoContext
都是独特的,由Scheme, Element type, ElementParams EncodingParams
生成。因此如果一个人在两台电脑前创建具有相同的Scheme, Element type, ElementParams EncodingParams
的CryptoContext
,那么这两个CryptoContext
应该是相同的。
2 解密
上节分析到,PALISADE内置有三种元素类型:Poly
、NativePoly
、DCRTPoly
。而加密的过程只针对DCRTPoly
元素类型,因此解密的过程自然只支持DCRTPoly
元素类型。下面是bgvrns-impl.cpp
类中对于Poly
与NativePoly
类型的元素不支持的说明:
template <>
DecryptResult LPAlgorithmBGVrns<Poly>::Decrypt(
const LPPrivateKey<Poly> privateKey, ConstCiphertext<Poly> ciphertext,
Poly *plaintext) const {
NOPOLY
}
template <>
DecryptResult LPAlgorithmBGVrns<NativePoly>::Decrypt(
const LPPrivateKey<NativePoly> privateKey,
ConstCiphertext<NativePoly> ciphertext, NativePoly *plaintext) const {
NONATIVEPOLY
}
NOPOLY,NONATIVEPOLY为开头预定义的错误信息:
#define NOPOLY \
std::string errMsg = "BGVrns does not support Poly. Use DCRTPoly instead."; \
PALISADE_THROW(not_implemented_error, errMsg);
#define NONATIVEPOLY \
std::string errMsg = \
"BGVrns does not support NativePoly. Use DCRTPoly instead."; \
PALISADE_THROW(not_implemented_error, errMsg);
因此重点分析针对DCRTPloy
类型的解密过程,该解密函数定义在900行左右。在分析源码之前我们先回顾一下PALISADE系列文章(三)【2】的解密过程:
PALISADE系列文章(四)【3】的公钥生成步骤中, p k 0 + s ∗ p k 1 = t ∗ e pk_0+s*pk_1 = t*e pk0+s∗pk1=t∗e,剩下的是模数乘上噪音,一个极小的误差,可以忽略不计。这就是我们大体的解密过程,不清楚的可以回顾一下PALISADE系列文章(三)
解密函数的函数定义以及一些变量声明如下:
template<>
//解密函数
DecryptResult LPAlgorithmBGVrns<DCRTPoly>::Decrypt(
const LPPrivateKey<DCRTPoly> privateKey,//传入私钥,密文封装对象,以及一个明文对象作为解密后的明文
ConstCiphertext<DCRTPoly> ciphertext, NativePoly *plaintext) const {
const auto cryptoParams =
std::static_pointer_cast<LPCryptoParametersBGVrns<DCRTPoly>>(
ciphertext->GetCryptoParameters());//获取加密参数
const NativeInteger t = cryptoParams->GetPlaintextModulus();//获取明文中的模数
const std::vector<DCRTPoly> &cv = ciphertext->GetElements();//获取密文对象中的密文向量
const DCRTPoly &s = privateKey->GetPrivateElement();//获取私钥元素
size_t sizeQl = cv[0].GetParams()->GetParams().size();
size_t sizeQ = s.GetParams()->GetParams().size();
size_t diffQl = sizeQ - sizeQl;
auto scopy(s);//复制私钥
scopy.DropLastElements(diffQl);
DCRTPoly sPower(scopy);
DCRTPoly b, ci;
下面是具体的解密过程:
b = cv[0];//密文向量的第一个元素
for (size_t i = 1; i < cv.size(); i++) {
ci = cv[i];//密文向量的后续元素
ci.SetFormat(Format::EVALUATION);
b += sPower * ci;
sPower *= scopy;
}
b.SetFormat(Format::COEFFICIENT);
第六行的运算就是解密的关节部分的运算:
最后我们将解密好的密文赋给解密函数传入的明文指针,实现解密的过程。
*plaintext = b.GetElementAtIndex(0).Mod(t);
return DecryptResult(plaintext->GetLength());
参考
【1】PALISADE Lattice Cryptography Library User Manual (v1.11.5)
【2】同系列文章:PALISADE(三)BGV原理分析与python实现
【3】同系列文章:PALISADE(四)密钥生成KeyGen