c++ - SEAL:平方运算后解密不正确,即使密文的噪声预算大于零

标签 c++ encryption cryptography seal

我对密文和最后的正方形进行了一系列计算。问题是,即使有足够的噪声预算来执行平方和重新线性化(在操作之前和之后),当我解密它时,我会得到不正确的结果。

奇怪的是,如果我解密和解码,然后在新的密文中再次编码和加密,即平方之前的数字,计算将正确执行。

我不明白问题出在哪里,因为如果设置的参数错误,那么我无论如何都会得到不正确的结果。

我指定使用分数编码器,其中积分部分有 64 个多项式系数,小数部分有 32 位精度(基数为 3),并且平方之前的所有计算都是在密文和明文之间执行。

这是我的意思的一个例子:

#include <vector>
#include "seal/seal.h"

using namespace std;
using namespace seal;



int main(int argc, char const *argv[])
{
    //Set parameters
    EncryptionParameters parms;
    parms.set_poly_modulus("1x^4096 + 1");
    parms.set_coeff_modulus(coeff_modulus_128(4096));
    parms.set_plain_modulus(1<<20);
    SEALContext context(parms);
    KeyGenerator keygen(context);
    PublicKey public_key = keygen.public_key();
    SecretKey secret_key = keygen.secret_key();
    EvaluationKeys ev_keys16;
    keygen.generate_evaluation_keys(16, ev_keys16);
    Encryptor encryptor(context, public_key);
    Evaluator evaluator(context);
    Decryptor decryptor(context, secret_key);
    FractionalEncoder fraencoder(context.plain_modulus(), context.poly_modulus(), 64, 32, 3);




    float data=0.5;
    float weight= 1.5;

    //encrypt data and encode weight

    Ciphertext encrypted_data;
    encryptor.encrypt(fraencoder.encode(data),encrypted_data);
    cout<<"Noise budget in a freshly encrypted: "<<decryptor.invariant_noise_budget(encrypted_data)<<endl;
    Plaintext encoded_weight=fraencoder.encode(weight);

    //Operation: (0.5*1.5)*5=3.75
    vector<Ciphertext> mul_vector(5);
    for(int i=0;i<5;i++){
        evaluator.multiply_plain(encrypted_data,encoded_weight,mul_vector[i]);
    }

    evaluator.add_many(mul_vector,encrypted_data);
    cout<<"Noise budget after 5 plain multiplications and 4 additions: "<<decryptor.invariant_noise_budget(encrypted_data)<<endl;

    //Operation: 3.75*4=15
    vector<Ciphertext> add_vector(4);
    for(int i=0;i<4;i++){
        add_vector[i]= Ciphertext(encrypted_data);
    }
    evaluator.add_many(add_vector,encrypted_data);

    cout<<"Noise budget after 4 additions: "<<decryptor.invariant_noise_budget(encrypted_data)<<endl;

    //Operation: (15-1.5)*1.5=20.25
    evaluator.sub_plain(encrypted_data,encoded_weight);
    evaluator.multiply_plain(encrypted_data,encoded_weight);

    cout<<"Noise budget after 1 plain sub and 1 plain multiplication: "<<decryptor.invariant_noise_budget(encrypted_data)<<endl;

    //Operation: (20.25*1.5)*6=182.25
    vector<Ciphertext> mul_vector2(6);
    for(int i=0;i<6;i++){
        evaluator.multiply_plain(encrypted_data,encoded_weight,mul_vector2[i]);
    }

    evaluator.add_many(mul_vector2,encrypted_data);
    cout<<"Noise budget after 6 plain multiplications and 5 additions: "<<decryptor.invariant_noise_budget(encrypted_data)<<endl;

    // here I decrypt, decode and encrypt again, to obtain the right result
    Plaintext tmp;
    float res;
    //If I remove the following 4 lines the final result is incorrect
    decryptor.decrypt(encrypted_data,tmp);
    res = fraencoder.decode(tmp);
    cout<<"Decrypted result before square: "<<res<<endl;
    encryptor.encrypt(fraencoder.encode(res),encrypted_data);

    //182.25^2=33215.1
    evaluator.square(encrypted_data);
    evaluator.relinearize(encrypted_data,ev_keys16);

    cout<<"Noise budget after square and relianearization: "<<decryptor.invariant_noise_budget(encrypted_data)<<endl;


    decryptor.decrypt(encrypted_data,tmp);
    res= fraencoder.decode(tmp);
    cout<<res<<endl;


    return 0;
}

我错过了什么?

最佳答案

问题是您的 plain_modulus 对于此计算来说太小。

如果您在末尾打印出 tmp (tmp.to_string()),您会发现它具有非常大的系数。请注意,这些系数是对 plain_modulus 取模的,因此其中许多系数预计看起来很大。尽管如此,res作为整数的无穷范数(即,如果您使用足够大的plain_modulus)是266441508,它略低于2< sup>29。由于您的 plain_modulus 只有 220,因此最终您将得到不正确的结果。您的重新编码会有所帮助,因为在最后一次计算之前,系数仍然不太大,并且重新编码多项式会将系数降低回无穷大范数 1(在您的情况下,基数 = 3)。

解决方案是将 plain_modulus 增加到至少 229。当然,这会导致更多的噪音增长,并且您已经非常接近噪音溢出,但它仍然有效。

关于c++ - SEAL:平方运算后解密不正确,即使密文的噪声预算大于零,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52059476/

相关文章:

c++ - 对象应该在 C++ 中删除自己吗?

c# - 将 static const char* 从 C++ 编码到 C#

ruby - 如何将十六进制字符串转换回二进制 'SecureRandom.random_bytes'?

hash - Merkle-Damgård 结构中的河豚?

c++ - Unordered_map 产生二级键

c++ - 什么时候 lambda 微不足道?

python - 将 Fernet key 写入文本文件会生成字节字符串而不是 ASCII 字符串

cryptography - 签署投票,因此无法确定用户,但可以检测到重复投票

c# - 如何使用 C# SDK 通过 AWS KMS 加密客户端

javascript - node.js中需要解密的数据如何加密?