Seal库官方示例(四):bgv_basics.cpp解析

本代码计算的是一个 x 8 x^8 x8,BGV和BFV的密文计算很相似,主要区别在于系数模选取以及噪声的控制。当然这是浅层代码层面,实际上的区别还有最大最小编码问题,乘法区别等等,当然这些能从深层代码细节(encrypt.cpp、evaluator.cpp等等)里看到,浅层里,SEAL库作者们已经为我们统一了。 (牛逼!(破声))
所以这个例四也没啥好写,和bfv里面长得太像了。

代码解析

参数设置

和BFV差不多,这里的系数模暂时选用的默认的,后续会有说明如何选取。

EncryptionParameters parms(scheme_type::bgv);
size_t poly_modulus_degree = 8192;
parms.set_poly_modulus_degree(poly_modulus_degree);
parms.set_coeff_modulus(CoeffModulus::BFVDefault(poly_modulus_degree));
parms.set_plain_modulus(PlainModulus::Batching(poly_modulus_degree, 20));
SEALContext context(parms);
print_line(__LINE__);
cout << "Set encryption parameters and print" << endl;
print_parameters(context);

Seal库官方示例(四):bgv_basics.cpp解析_第1张图片

密钥生成

也和BFV基本一样

KeyGenerator keygen(context);
SecretKey secret_key = keygen.secret_key();
PublicKey public_key;
keygen.create_public_key(public_key);
RelinKeys relin_keys;
keygen.create_relin_keys(relin_keys);
Encryptor encryptor(context, public_key);
Evaluator evaluator(context);
Decryptor decryptor(context, secret_key);

这里叨叨两句,从论文里看,BGV和BFV的评估密钥生成貌似应该是不一样的,BGV定义的是密钥交换,BFV是重线性化。然后去找了一下源码,发现生成重线性化密钥的时候是调用了密钥交换方法的。又跑回去看看原来的文章,发现重线性化基本上就是密钥交换,核心都是把密钥的乘积项处理了一下,那么代码能统一到一起就不见怪了。

编码

插槽数同样是阶数,编码前同样看作一个 2 × N 2 2 \times \frac N2 2×2N的矩阵

BatchEncoder batch_encoder(context);
size_t slot_count = batch_encoder.slot_count();
size_t row_size = slot_count / 2;
cout << "Plaintext matrix row size: " << row_size << endl;
vector<uint64_t> pod_matrix(slot_count, 0ULL);
pod_matrix[0] = 1ULL;
pod_matrix[1] = 2ULL;
pod_matrix[2] = 3ULL;
pod_matrix[3] = 4ULL;

cout << "Input plaintext matrix:" << endl;
print_matrix(pod_matrix, row_size);
Plaintext x_plain;
cout << "Encode plaintext matrix to x_plain:" << endl;
batch_encoder.encode(pod_matrix, x_plain);

Seal库官方示例(四):bgv_basics.cpp解析_第2张图片

加密

Ciphertext x_encrypted;
print_line(__LINE__);
cout << "Encrypt x_plain to x_encrypted." << endl;
encryptor.encrypt(x_plain, x_encrypted);
cout << "    + noise budget in freshly encrypted x: " << decryptor.invariant_noise_budget(x_encrypted) << " bits"
     << endl;
cout << endl;

image.png

同态计算以及解密

计算到8次幂,采用的是边计算边解密

//计算二次幂
print_line(__LINE__);
cout << "Compute and relinearize x_squared (x^2)," << endl;
Ciphertext x_squared;
evaluator.square(x_encrypted, x_squared);
cout << "    + size of x_squared: " << x_squared.size() << endl;
evaluator.relinearize_inplace(x_squared, relin_keys);
cout << "    + size of x_squared (after relinearization): " << x_squared.size() << endl;
cout << "    + noise budget in x_squared: " << decryptor.invariant_noise_budget(x_squared) << " bits" << endl;
Plaintext decrypted_result;
decryptor.decrypt(x_squared, decrypted_result);
vector<uint64_t> pod_result;
batch_encoder.decode(decrypted_result, pod_result);
cout << "    + result plaintext matrix ...... Correct." << endl;
print_matrix(pod_result, row_size);

//计算四次幂
print_line(__LINE__);
cout << "Compute and relinearize x_4th (x^4)," << endl;
Ciphertext x_4th;
evaluator.square(x_squared, x_4th);
cout << "    + size of x_4th: " << x_4th.size() << endl;
evaluator.relinearize_inplace(x_4th, relin_keys);
cout << "    + size of x_4th (after relinearization): " << x_4th.size() << endl;
cout << "    + noise budget in x_4th: " << decryptor.invariant_noise_budget(x_4th) << " bits" << endl;
decryptor.decrypt(x_4th, decrypted_result);
batch_encoder.decode(decrypted_result, pod_result);
cout << "    + result plaintext matrix ...... Correct." << endl;
print_matrix(pod_result, row_size);

//计算八次幂
print_line(__LINE__);
cout << "Compute and relinearize x_8th (x^8)," << endl;
Ciphertext x_8th;
evaluator.square(x_4th, x_8th);
cout << "    + size of x_8th: " << x_8th.size() << endl;
evaluator.relinearize_inplace(x_8th, relin_keys);
cout << "    + size of x_8th (after relinearization): " << x_8th.size() << endl;
cout << "    + noise budget in x_8th: " << decryptor.invariant_noise_budget(x_8th) << " bits" << endl;
cout << "NOTE: Decryption can be incorrect if noise budget is zero." << endl;

从结果可以看到,计算8次幂后,噪声已经超过了噪声上限,噪声预算消耗完毕,不能正确的解密。因为这里只调用了重线性化来缩减密文的规模,还没有进行噪声的控制。
Seal库官方示例(四):bgv_basics.cpp解析_第3张图片

接下来采用模交换来控制噪声,BFV是可以不用的哦,乘法自带。

cout << endl;
cout << "~~~~~~ Use modulus switching to calculate x^8. ~~~~~~" << endl;
print_line(__LINE__);
cout << "Encrypt x_plain to x_encrypted." << endl;
encryptor.encrypt(x_plain, x_encrypted);
cout << "    + noise budget in freshly encrypted x: " << decryptor.invariant_noise_budget(x_encrypted) << " bits"
     << endl;
cout << endl;

//计算二次幂
print_line(__LINE__);
cout << "Compute and relinearize x_squared (x^2)," << endl;
cout << "    + noise budget in x_squared (previously): " << decryptor.invariant_noise_budget(x_squared) << " bits"
     << endl;
evaluator.square(x_encrypted, x_squared);
evaluator.relinearize_inplace(x_squared, relin_keys);
evaluator.mod_switch_to_next_inplace(x_squared);
cout << "    + noise budget in x_squared (with modulus switching): " << decryptor.invariant_noise_budget(x_squared)
     << " bits" << endl;
decryptor.decrypt(x_squared, decrypted_result);
batch_encoder.decode(decrypted_result, pod_result);
cout << "    + result plaintext matrix ...... Correct." << endl;
print_matrix(pod_result, row_size);

//计算四次幂
print_line(__LINE__);
cout << "Compute and relinearize x_4th (x^4)," << endl;
cout << "    + noise budget in x_4th (previously): " << decryptor.invariant_noise_budget(x_4th) << " bits" << endl;
evaluator.square(x_squared, x_4th);
evaluator.relinearize_inplace(x_4th, relin_keys);
evaluator.mod_switch_to_next_inplace(x_4th);
cout << "    + noise budget in x_4th (with modulus switching): " << decryptor.invariant_noise_budget(x_4th)
     << " bits" << endl;
decryptor.decrypt(x_4th, decrypted_result);
batch_encoder.decode(decrypted_result, pod_result);
cout << "    + result plaintext matrix ...... Correct." << endl;
print_matrix(pod_result, row_size);
//计算八次幂
print_line(__LINE__);
cout << "Compute and relinearize x_8th (x^8)," << endl;
cout << "    + noise budget in x_8th (previously): " << decryptor.invariant_noise_budget(x_8th) << " bits" << endl;
evaluator.square(x_4th, x_8th);
evaluator.relinearize_inplace(x_8th, relin_keys);
evaluator.mod_switch_to_next_inplace(x_8th);
cout << "    + noise budget in x_8th (with modulus switching): " << decryptor.invariant_noise_budget(x_8th)
     << " bits" << endl;
decryptor.decrypt(x_4th, decrypted_result);
batch_encoder.decode(decrypted_result, pod_result);
cout << "    + result plaintext matrix ...... Correct." << endl;
print_matrix(pod_result, row_size);

尽管看到了计算 x 2 x^2 x2的时候噪声预算貌似减小了,但从后面计算能够看出,噪声的消耗显著变慢,所以使用好bgv方案,需要在合适的位置假如modulus switching,通过合适的系数模选择能够来调整这个速率。
Seal库官方示例(四):bgv_basics.cpp解析_第4张图片

你可能感兴趣的:(密码学-隐私计算,同态加密)