BFV源码分析
1.设置EncryptionParameters类实例
1 2 3 4 5 6 7 8 EncryptionParameters parms(scheme_type::bfv); 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(2048) ;
poly_modulus_degree(多项式模数):2的正幂,表示分圆多项式的degree。值越大则密文大小越大,导致所有操作更慢但能够实现更加复杂的加密计算,推荐值为1024/2048/4096/8192/16384/32768或更大
coeff_modulus([密文]系数模数):不同质数的乘积,每个质数最多60位。其位长是指其质因数位长之和,值越大噪声预算越大,意味着更强的加密计算能力,总位长受到poly_modulus_degree限制
1 2 3 4 5 6 7 8 9 10 +---------------------+---------------------------- ---+ | poly_modulus_degree | 最大 coeff_modulus 位长 | +---------------------+---------------------------- ---+ | 1024 | 27 | | 2048 | 54 | | 4096 | 109 | | 8192 | 218 | | 16384 | 438 | | 32768 | 881 | +---------------------+---------------------------- ---+
plain_modulus(明文模数,仅适用于BFV方案):可以是任意正整数。它决定了明文数据类型的大小和乘法中噪声预算的消耗,因此必须尽量保持明文数据类型尽可能小。
新加密密文的噪声预算:~\(log_{2}(coeff\_modulus/plain\_modulus)\) (位) 同态乘法的噪声预算消耗为\(log_{2}(plain\_modulus)+(other\ terms)\) .
2. 构造SEALContext对象
1 2 3 4 5 6 7 8 9 10 SEALContext context (parms) ;print_line (__LINE__); cout << "Set encryption parameters and print" << endl;print_parameters (context); cout << "Parameter validation (success): " << context.parameter_error_message () << endl; cout << endl; cout << "~~~~~~ A naive way to calculate 4(x^2+1)(x+1)^2. ~~~~~~" << endl;
3. 设置KeyGenerator类实例
用于生成公私钥对 1 2 3 4 KeyGenerator keygen(context) SecretKey secret_key = keygen.secret_key() PublicKey public_key keygen.create_public_key(public_key)
4. 设置Encryptor/Evaluator/Decryptor类实例
1 2 3 Encryptor encryptor (context, public_key) ; Evaluator evaluator (context) ;Decryptor decryptor (context, secret_key) ;
5.示例
对于加密的x=6,计算\(4x^{4}+8x^{3}+8x^{2}+8x+4\)
首先创建一个包含常数6的明文。对于明文元素,使用构造函数将所需的多项式作为一个字符串,其系数表示为十六进制数
1 2 3 4 5 print_line(__LINE__ ) ;int x = 6 ; Plaintext x_plain(to_string (x ) ); cout << "Express x = " + to _string(x ) + " as a plaintext polynomial 0x" + x_plain.to _string() + "." << endl;
然后对明文进行加密,生成密文
1 2 3 4 print_line (__LINE__); Ciphertext x_encrypted; cout << "Encrypt x_plain to x_encrypted." << endl; encryptor.encrypt (x_plain, x_encrypted);
在SEAL中,一个有效的密文由两个或多个多项式组成,它们的系数是整数mod(在coeff_modulus中素数的乘积)。密文中多项式的个数称为它的"size",由Ciphertext::size()给出。新加密的密文size总是2.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 cout << " + size of freshly encrypted x: " << x_encrypted.size () << endl; cout << " + noise budget in freshly encrypted x: " << decryptor.invariant_noise_budget (x_encrypted) << " bits" << endl; Plaintext x_decrypted; cout << " + decryption of x_encrypted: " ; decryptor.decrypt (x_encrypted, x_decrypted); cout << "0x" << x_decrypted.to_string () << " ...... Correct." << endl;
当使用SEAL时,以最小化最长的顺序乘法链的方式进行计算通常是有利的。换句话说,加密计算最好以最小化计算乘法深度的方式进行评估,因为总噪声预算消耗与乘法深度成正比。例如,在计算给定多项式时,因式分解多项式是有利的:
\(4x^{4}+8x^{3}+8x^{2}+8x+4=4(x+1)^{2}*(x^{2}+1)\)
因此我们可以分别计算\(x^{2}+1\) 和\((x+1)^{2}\) ,再将其相乘,最后乘上一个明文'4'.
首先计算\(x^{2}\) ,并加上一个明文'1'.
1 2 3 4 5 6 7 8 print_line(__LINE__ ) ; cout << "Compute x_sq_plus_one (x^2+1)." << endl; Ciphertext x_sq_plus_one; evaluator.square(x_encrypted, x_sq_plus_one); Plaintext plain_one("1" ) ; evaluator.add_plain_inplace(x_sq_plus_one , plain_one ) ;
再计算\((x+1)^{2}\)
1 2 3 4 5 6 7 8 9 10 11 print_line(__LINE__ ) ; cout << "Compute x_plus_one_sq ((x+1)^2)." << endl; Ciphertext x_plus_one_sq; evaluator.add_plain(x_encrypted , plain_one , x_plus_one_sq ) ; evaluator.square_inplace(x_plus_one_sq ) ; cout << " + size of x_plus_one_sq: " << x_plus_one_sq.size() << endl; cout << " + noise budget in x_plus_one_sq: " << decryptor.invariant_noise_budget(x_plus_one_sq ) << " bits" << endl; cout << " + decryption of x_plus_one_sq: " ; decryptor.decrypt(x_plus_one_sq, decrypted_result); cout << "0x" << decrypted_result.to _string() << " ...... Correct." << endl;
最后计算\(4(x+1)^{2}*(x^{2}+1)\)
1 2 3 4 5 6 7 8 9 10 11 12 13 print_line (__LINE__); cout << "Compute encrypted_result (4(x^2+1)(x+1)^2)." << endl; Ciphertext encrypted_result;Plaintext plain_four ("4" ) ; evaluator.multiply_plain_inplace (x_sq_plus_one, plain_four); evaluator.multiply (x_sq_plus_one, x_plus_one_sq, encrypted_result); cout << " + size of encrypted_result: " << encrypted_result.size () << endl; cout << " + noise budget in encrypted_result: " << decryptor.invariant_noise_budget (encrypted_result) << " bits" << endl; cout << "NOTE: Decryption can be incorrect if noise budget is zero." << endl; cout << endl; cout << "~~~~~~ A better way to calculate 4(x^2+1)(x+1)^2. ~~~~~~" << endl;
当噪声预算达到0,则意味着不能期望解密给出正确的结果。在上述计算方法中,由于密文x_sq_plus_one和x_plus_one_sq都由三个多项式组成(这是由平方运算造成的),对大密文的同态运算比小密文的计算消耗更多的噪声预算。
"Relinearization"是一种将密文的size刷新为初始size(2)的一种操作。因此,在下一次乘法之前对密文进行重新线性化操作,可以降低噪声增长,优化性能。"Relinearization"需要特殊的"Relinearization密钥",可以将其视为一种公钥,使用KeyGenerator生成。在BFV和CKKS方案中都有类似用到。
1 2 3 4 5 print_line(__LINE__ ) ; cout << "Generate relinearization keys." << endl; RelinKeys relin_keys; keygen.create_relin_keys(relin_keys ) ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 print_line (__LINE__); cout << "Compute and relinearize x_squared (x^2)," << endl; cout << string (13 , ' ' ) << "then compute x_sq_plus_one (x^2+1)" << 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; evaluator.add_plain (x_squared, plain_one, x_sq_plus_one); cout << " + noise budget in x_sq_plus_one: " << decryptor.invariant_noise_budget (x_sq_plus_one) << " bits" << endl; cout << " + decryption of x_sq_plus_one: " ; decryptor.decrypt (x_sq_plus_one, decrypted_result); cout << "0x" << decrypted_result.to_string () << " ...... Correct." << endl;print_line (__LINE__); Ciphertext x_plus_one; cout << "Compute x_plus_one (x+1)," << endl; cout << string (13 , ' ' ) << "then compute and relinearize x_plus_one_sq ((x+1)^2)." << endl; evaluator.add_plain (x_encrypted, plain_one, x_plus_one); evaluator.square (x_plus_one, x_plus_one_sq); cout << " + size of x_plus_one_sq: " << x_plus_one_sq.size () << endl; evaluator.relinearize_inplace (x_plus_one_sq, relin_keys); cout << " + noise budget in x_plus_one_sq: " << decryptor.invariant_noise_budget (x_plus_one_sq) << " bits" << endl; cout << " + decryption of x_plus_one_sq: " ; decryptor.decrypt (x_plus_one_sq, decrypted_result); cout << "0x" << decrypted_result.to_string () << " ...... Correct." << endl;print_line (__LINE__); cout << "Compute and relinearize encrypted_result (4(x^2+1)(x+1)^2)." << endl; evaluator.multiply_plain_inplace (x_sq_plus_one, plain_four); evaluator.multiply (x_sq_plus_one, x_plus_one_sq, encrypted_result); cout << " + size of encrypted_result: " << encrypted_result.size () << endl; evaluator.relinearize_inplace (encrypted_result, relin_keys); cout << " + size of encrypted_result (after relinearization): " << encrypted_result.size () << endl; cout << " + noise budget in encrypted_result: " << decryptor.invariant_noise_budget (encrypted_result) << " bits" << endl; cout << endl; cout << "NOTE: Notice the increase in remaining noise budget." << endl;
主流FHE方案比较
1.FHEW/TFHE/GSW
快速比较
支持任意布尔电路
快速bootstrapping(噪声刷新过程,减少因密文计算而产生的噪声,降低失败的可能性)
2.BGV/BFV
在整数向量上进行高效的SIMD计算(使用批处理)
快速高精度整数算术
快速向量的标量乘法
Leveled design(通常不使用bootstrapping)
3.CKKS
快速多项式近似计算
相对快速的倒数和离散傅里叶变换
深度近似计算,如逻辑回归学习
在实数向量上进行高效的SIMD计算(使用批处理)
Leveled design(通常不使用bootstrapping)
参考:
https://blog.csdn.net/ldxcsdn/category_11390861.html