奎屯网站制作,学推广网络营销去哪里,做响应式网站用什么框架,青岛网络优化公司前面介绍 BFV 和 CKKS 加密方案#xff0c;这两者更为常用。并且也解释了 Batch Encoder 和 级别的概念#xff0c;这对接下来演示 BGV 会很有帮助。
一、BGV简介 BGV (Brakerski-Gentry-Vaikuntanathan) 方案 是一种基于环学习同态加密#xff08;RLWE#xff09;问题的加… 前面介绍 BFV 和 CKKS 加密方案这两者更为常用。并且也解释了 Batch Encoder 和 级别的概念这对接下来演示 BGV 会很有帮助。
一、BGV简介 BGV (Brakerski-Gentry-Vaikuntanathan) 方案 是一种基于环学习同态加密RLWE问题的加密方案。BGV 方案可以实现任意计算电路的同态加密特别适合于加密数据的复杂运算。
特点
同态运算支持加法和乘法的任意组合这意味着它可以评估任意计算电路。级联密文密文可以通过一系列同态运算来处理而不需要在每一步进行解密和重新加密。噪声管理在每次同态运算之后密文中的噪声会增加。BGV 方案采用了噪声管理技术例如重新线性化和模数切换来控制噪声增长确保运算的正确性。
优点
灵活性支持任意复杂的计算。效率通过噪声管理技术提高了运算效率。安全性基于环学习同态加密问题的安全性高。
缺点
复杂性实现和使用BGV方案比一些其他方案更为复杂。资源消耗噪声管理和重新线性化等操作增加了计算和存储的开销。
二、3种方案比较
先看发展顺序
BGV 方案2011年 Brakerski、Gentry 和 Vaikuntanathan 提出。BFV 方案2012年 Fan 和 Vercauteren 提出。CKKS 方案2017年 Cheon、Kim、Kim 和 Song 提出。
分别的适用场景
如果需要对整数进行精确计算BFV 方案是一个好的选择。如果需要对浮点数进行近似计算CKKS 方案是更合适的。如果需要复杂的计算电路BGV 方案提供了最大的灵活性。 每种方案都有其独特的优势和适用场景在实际应用中选择适合的方案可以最大化地发挥同态加密技术的优势。
三、BGV 示例 在本示例中计算8次多项式 并且在整数 1、2、3、4上的加密 。多项式的系数可以看作是明文输入计算在 plain_modulus 1032193 模数下进行。 在BGV方案中对加密数据进行计算类似于BFV。这个例子的主要目的是解释BFV和BGV在密文系数模数选择和噪声控制方面的区别。
3.1 参数设置和创建实例
这里先使用 BFVDefault 创建 coeff_modulus后面会介绍如何更好的设置。
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);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); 这里想再次强调一下因为用的是 Batch 批处理所以在设置 plain_modulus 的时候要求是与 2倍 poly_modulus_degree 同余 1 的素数这与普通的 Encoder 要求不同。上面代码中是用 PlainModulus::Batching 自动生成满足条件的随机数。 这里输出设置的参数 3.2 设置输入并编码 批处理和槽操作在 BFV 和 BGV 中是相同的
BatchEncoder batch_encoder(context);
size_t slot_count batch_encoder.slot_count();
size_t row_size slot_count / 2; 这里特意设置 row_size 变量是因为之前讲批处理的时候强调过内部在逻辑上会编码成两行故其实就是 。当然这个结构对于编码和计算是基本无感的只有在考虑行旋转和列旋转的时候会有影响这个下一篇会具体介绍挖坑 1。
vectoruint64_t pod_matrix(slot_count, 0ULL);
pod_matrix[0] 1ULL;
pod_matrix[1] 2ULL;
pod_matrix[2] 3ULL;
pod_matrix[3] 4ULL;
Plaintext x_plain;
batch_encoder.encode(pod_matrix, x_plain);
这里对编码结果打印输出一下 3.3 直接运算
Ciphertext x_encrypted;
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;
这里先对输入进行加密并输出噪声预算 先计算
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; 因为是 密文乘密文为了减少乘法后的密文大小这里进行了重新线性化并输出了噪声预算同时进行解密验证 可以看出运算中间结果是正确的并且重新线性化后密文大小从3减小到2。 再计算
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;
同样进行了重新线性化并输出目前噪声预算同时进行解密验证 可以看出这里的噪声预算下降的特别快只剩 35 bits 了。 最后计算
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; 噪声预算已经达到0这意味着解密无法得到正确的结果。故此引出 BGV需要模数切换以减少噪声增长 3.4 加入模数切换的运算
下面演示在每次重新线性化后插入模数切换避免啰嗦这里直接完整计算
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;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;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_8th, decrypted_result);
batch_encoder.decode(decrypted_result, pod_result);
这里对中间结果也进行解密并输出其噪声预算的变化 这里仔细对比可以发现虽然通过模数切换 x_squared 的噪声预算比之前少但噪声预算的消耗速率较慢故最后可以正确解密。
四、总结 通过之前的介绍实验我们能发现有时候进行模数切换会损耗噪声预算但是进行到一定乘法深度后再进行切换就不会损耗噪声这种情况是一定适合加入模数切换的。 同时上面发现虽然降低了 x_squared 的噪声预算但是噪声预算的消耗减慢故这种情况也适合加入模数切换。 但是这些不意味着在每次计算后都应该进行模数切换因为要权衡减少的预算和减缓消耗的速度最好自己进行实验比对。故为了在应用中实现噪声预算的最佳消耗速率需要仔细选择插入模数切换的位置并手动选择 coeff_modulus。 下篇介绍对密文进行的 行旋转 和 列旋转未完待续。。。