SEAL全同态加密开源库(十五) rotation-源码浅析

2021SC@SDUSC

2021-12-27

前言

本篇开始我将讨论SEAL中rotation.cpp的代码实现。

简介

BFV方案(使用BatchEncoder)和CKKS方案都支持对加密数字进行native计算。除了slot-wise计算外,还可以循环地旋转加密向量。

代码分析

void example_rotation_bfv()

先是和前文类似的设置一些参数。

    print_example_banner("Example: Rotation / Rotation in BFV");

    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(PlainModulus::Batching(poly_modulus_degree, 20));

    SEALContext context(parms);
    print_parameters(context);
    cout << endl;

    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);

    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] = 0ULL;
    pod_matrix[1] = 1ULL;
    pod_matrix[2] = 2ULL;
    pod_matrix[3] = 3ULL;
    pod_matrix[row_size] = 4ULL;
    pod_matrix[row_size + 1] = 5ULL;
    pod_matrix[row_size + 2] = 6ULL;
    pod_matrix[row_size + 3] = 7ULL;

    cout << "Input plaintext matrix:" << endl;
    print_matrix(pod_matrix, row_size);

首先,我们使用BatchEncoder将矩阵编码成明文。我们像往常一样加密明文。

Plaintext plain_matrix;
print_line(__LINE__);
cout << "Encode and encrypt." << endl;
batch_encoder.encode(pod_matrix, plain_matrix);
Ciphertext encrypted_matrix;
encryptor.encrypt(plain_matrix, encrypted_matrix);//加密结果放在encrypted_matrix
cout << "    + Noise budget in fresh encryption: "
    << decryptor.invariant_noise_budget(encrypted_matrix) << " bits" << endl;
cout << endl;

旋转需要另一种特殊的键,叫做“伽罗瓦键 Galois keys”。这些很容易从密钥生成器获得。

    GaloisKeys galois_keys;
    keygen.create_galois_keys(galois_keys);

现在将两个矩阵行向左旋转3步,解密、解码和打印。

    print_line(__LINE__);
    cout << "Rotate rows 3 steps left." << endl;
    evaluator.rotate_rows_inplace(encrypted_matrix, 3, galois_keys);
    Plaintext plain_result;
    cout << "    + Noise budget after rotation: " << decryptor.invariant_noise_budget(encrypted_matrix) << " bits"
         << endl;
    cout << "    + Decrypt and decode ...... Correct." << endl;
    decryptor.decrypt(encrypted_matrix, plain_result);
    batch_encoder.decode(plain_result, pod_matrix);
    print_matrix(pod_matrix, row_size);

我们还可以旋转列,即交换行。

    print_line(__LINE__);
    cout << "Rotate columns." << endl;
    evaluator.rotate_columns_inplace(encrypted_matrix, galois_keys);
    cout << "    + Noise budget after rotation: " << decryptor.invariant_noise_budget(encrypted_matrix) << " bits"
         << endl;
    cout << "    + Decrypt and decode ...... Correct." << endl;
    decryptor.decrypt(encrypted_matrix, plain_result);
    batch_encoder.decode(plain_result, pod_matrix);
    print_matrix(pod_matrix, row_size);

最后,我们将行向右旋转4步,解密、解码和打印。

    print_line(__LINE__);
    cout << "Rotate rows 4 steps right." << endl;
    evaluator.rotate_rows_inplace(encrypted_matrix, -4, galois_keys);
    cout << "    + Noise budget after rotation: " << decryptor.invariant_noise_budget(encrypted_matrix) << " bits"
         << endl;
    cout << "    + Decrypt and decode ...... Correct." << endl;
    decryptor.decrypt(encrypted_matrix, plain_result);
    batch_encoder.decode(plain_result, pod_matrix);
    print_matrix(pod_matrix, row_size);

**注意,旋转不消耗任何噪音预算。**然而,只有当特殊素数至少与其他素数一样大时,才会出现这种情况。relinearization也是如此。Microsoft SEAL不要求特殊的prime具有任何特定的大小,因此确保这种情况是由用户来做的。

void example_rotation_ckks()

需要注意的是,CKKS方案中的旋转与BFV中的旋转非常相似,过程相似,我们不再作具体的分析。

    EncryptionParameters parms(scheme_type::ckks);

    size_t poly_modulus_degree = 8192;
    parms.set_poly_modulus_degree(poly_modulus_degree);
    parms.set_coeff_modulus(CoeffModulus::Create(poly_modulus_degree, {
    
     40, 40, 40, 40, 40 }));

    SEALContext context(parms);
    print_parameters(context);
    cout << endl;

    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);
    GaloisKeys galois_keys;
    keygen.create_galois_keys(galois_keys);
    Encryptor encryptor(context, public_key);
    Evaluator evaluator(context);
    Decryptor decryptor(context, secret_key);

    CKKSEncoder ckks_encoder(context);

    size_t slot_count = ckks_encoder.slot_count();
    cout << "Number of slots: " << slot_count << endl;
    vector<double> input;
    input.reserve(slot_count);
    double curr_point = 0;
    double step_size = 1.0 / (static_cast<double>(slot_count) - 1);
    for (size_t i = 0; i < slot_count; i++, curr_point += step_size)
    {
    
    
        input.push_back(curr_point);
    }
    cout << "Input vector:" << endl;
    print_vector(input, 3, 7);

    auto scale = pow(2.0, 50);

    print_line(__LINE__);
    cout << "Encode and encrypt." << endl;
    Plaintext plain;
    ckks_encoder.encode(input, scale, plain);
    Ciphertext encrypted;
    encryptor.encrypt(plain, encrypted);

    Ciphertext rotated;
    print_line(__LINE__);
    cout << "Rotate 2 steps left." << endl;
    evaluator.rotate_vector(encrypted, 2, galois_keys, rotated);
    cout << "    + Decrypt and decode ...... Correct." << endl;
    decryptor.decrypt(rotated, plain);
    vector<double> result;
    ckks_encoder.decode(plain, result);
    print_vector(result, 3, 7);

使用CKKS方案,还可以使用Evaluator:: complex_共轭来计算加密复数向量上的复共轭。这其实是一种旋转,也需要伽罗瓦键。

运行

即将上述两种方案依次运行即可。

void example_rotation()
{
    
    
    print_example_banner("Example: Rotation");

    /*
    Run all rotation examples.
    */
    example_rotation_bfv();
    example_rotation_ckks();
}

运行效果展示

+-----------------------------------+
|         Example: Rotation         |
+-----------------------------------+

+-----------------------------------------------------+
|         Example: Rotation / Rotation in BFV         |
+-----------------------------------------------------+
/
| Encryption parameters :
|   scheme: BFV
|   poly_modulus_degree: 8192
|   coeff_modulus size: 218 (43 + 43 + 44 + 44 + 44) bits
|   plain_modulus: 1032193
\

Plaintext matrix row size: 4096
Input plaintext matrix:

    [  0,  1,  2,  3,  0, ...,  0,  0,  0,  0,  0 ]
    [  4,  5,  6,  7,  0, ...,  0,  0,  0,  0,  0 ]

Line  62 --> Encode and encrypt.
    + Noise budget in fresh encryption: 146 bits

Line  81 --> Rotate rows 3 steps left.
    + Noise budget after rotation: 142 bits
    + Decrypt and decode ...... Correct.

    [  3,  0,  0,  0,  0, ...,  0,  0,  0,  1,  2 ]
    [  7,  0,  0,  0,  0, ...,  0,  0,  4,  5,  6 ]

Line  95 --> Rotate columns.
    + Noise budget after rotation: 142 bits
    + Decrypt and decode ...... Correct.

    [  7,  0,  0,  0,  0, ...,  0,  0,  4,  5,  6 ]
    [  3,  0,  0,  0,  0, ...,  0,  0,  0,  1,  2 ]

Line 108 --> Rotate rows 4 steps right.
    + Noise budget after rotation: 142 bits
    + Decrypt and decode ...... Correct.

    [  0,  4,  5,  6,  7, ...,  0,  0,  0,  0,  0 ]
    [  0,  0,  1,  2,  3, ...,  0,  0,  0,  0,  0 ]


+------------------------------------------------------+
|         Example: Rotation / Rotation in CKKS         |
+------------------------------------------------------+
/
| Encryption parameters :
|   scheme: CKKS
|   poly_modulus_degree: 8192
|   coeff_modulus size: 200 (40 + 40 + 40 + 40 + 40) bits
\

Number of slots: 4096
Input vector:

    [ 0.0000000, 0.0002442, 0.0004884, ..., 0.9995116, 0.9997558, 1.0000000 ]

Line 173 --> Encode and encrypt.
Line 181 --> Rotate 2 steps left.
    + Decrypt and decode ...... Correct.

    [ 0.0004884, 0.0007326, 0.0009768, ..., 1.0000000, -0.0000000, 0.0002442 ]

+---------------------------------------------------------+
| The following examples should be executed while reading |
| comments in associated files in native/examples/.       |
+---------------------------------------------------------+
| Examples                   | Source Files               |
+----------------------------+----------------------------+
| 1. BFV Basics              | 1_bfv_basics.cpp           |
| 2. Encoders                | 2_encoders.cpp             |
| 3. Levels                  | 3_levels.cpp               |
| 4. CKKS Basics             | 4_ckks_basics.cpp          |
| 5. Rotation                | 5_rotation.cpp             |
| 6. Serialization           | 6_serialization.cpp        |
| 7. Performance Test        | 7_performance.cpp          |
+----------------------------+----------------------------+
[     82 MB] Total allocation from the memory pool

结语

本文我们分析了SEAL对于rotation的实现机制。总体来说还是比前几篇难度低一些,有一些集大成者的感觉。这也是从底层向上层分析的收获吧。

猜你喜欢

转载自blog.csdn.net/ldxcsdn/article/details/122180791