2021SC@SDUSC-SEAL全同态加密库(十)

SEAL全同态加密库(十)

一.levels

在Microsoft SEAL中,一组加密参数(不包括随机数生成器)由参数的SHA-3 哈希唯一标识。这个哈希称为“parms_id”,可以在任何时候方便地访问和打印。一旦任何参数改变,哈希值就会改变。

当创建SEALContext从给定EncryptionParameters实例时,Microsoft SEAL自动创建一个所谓的“模数转换链”,这是一个来源于原始set的 a chain of 其他加密参数。模数转换链中的参数与原始参数是相同的除了系数模量的大小沿着链向下递减。更准确地说,链中的每个参数集都试图从前一个集合中移除最后一个系数模量素数;这种情况一直持续到参数集不再有效为止(例如,plain_modules大于剩余的coeff_modules)。很容易遍历链并访问所有参数集。此外,链中的每个参数集都有一个“链索引”,该索引表示其在链中的位置,因此最后一个参数集的索引为0。我们说,一组加密参数或携带这些加密参数的对象在链中的级别高于另一组参数,如果它的链索引更大,例如它处于链的较早阶段。

在创建SEALContext时链中的每一组参数都包含执行的惟一的预计算,并存储在SEALContext::ContextData对象中。该链基本上是一个SEALContext::ContextData对象的链表,可以在任何时候通过SEALContext轻松地访问它。每个节点都可以通过其特定加密参数的parms_id来标识(poly_modulus_degree保持不变,但coeff_modul_modules会变化。

在SEAL中有一个重要的level的概念,根据示例代码里的注释,可以理解为SEAL根据默认的参数创建了一个modulus switching chain ,在同一个链上的加密实例除了coefficient modulus 其他都相同。下面示例代码给的一个解释:

              special prime +---------+
                                  |
                                  v
coeff_modulus: {
    
     50, 30, 30, 50, 50 }  +---+  Level 4 (all keys; `key level')
                                           |
                                           |
    coeff_modulus: {
    
     50, 30, 30, 50 }  +---+  Level 3 (highest `data level')
                                           |
                                           |
        coeff_modulus: {
    
     50, 30, 30 }  +---+  Level 2
                                           |
                                           |
            coeff_modulus: {
    
     50, 30 }  +---+  Level 1
                                           |
                                           |
                coeff_modulus: {
    
     50 }  +---+  Level 0 (lowest level)

有方便的访问方法 SEALContext::ContextData 
SEALContext::key_context_data(): access to key level ContextData
SEALContext::first_context_data(): access to highest data level ContextData
SEALContext::last_context_data(): access to lowest level ContextData

我们遍历链并为每个参数集打印parms_id:

print_line(__LINE__);
cout << "Print the modulus switching chain." << endl;
 /*
First print the key level parameter information.
*/
auto context_data = context->key_context_data();
cout << "----> Level (chain index): " << context_data->chain_index();
cout << " ...... key_context_data()" << endl;
cout << "      parms_id: " << context_data->parms_id() << endl;
cout << "      coeff_modulus primes: ";
cout << hex;
for(const auto &prime : context_data->parms().coeff_modulus())
{
    
    
    cout << prime.value() << " ";
}
cout << dec << endl;
cout << "\\" << endl;
cout << " \\-->";

/*
Next iterate over the remaining (data) levels.
*/
context_data = context->first_context_data();
while (context_data)
{
    
    
    cout << " Level (chain index): " << context_data->chain_index();
    if (context_data->parms_id() == context->first_parms_id())
    {
    
    
        cout << " ...... first_context_data()" << endl;
    }
    else if (context_data->parms_id() == context->last_parms_id())
    {
    
    
        cout << " ...... last_context_data()" << endl;
    }
    else
    {
    
    
        cout << endl;
    }
    cout << "      parms_id: " << context_data->parms_id() << endl;
    cout << "      coeff_modulus primes: ";
    cout << hex;
    for(const auto &prime : context_data->parms().coeff_modulus())
    {
    
    
        cout << prime.value() << " ";
    }
    cout << dec << endl;
    cout << "\\" << endl;
    cout << " \\-->";

    /*
    Step forward in the chain.
    */
    context_data = context_data->next_context_data();
}
cout << " End of chain reached" << endl << endl;

/*
We create some keys and check that indeed they appear at the highest level.
*/
KeyGenerator keygen(context);
auto public_key = keygen.public_key();
auto secret_key = keygen.secret_key();
auto relin_keys = keygen.relin_keys();
auto galois_keys = keygen.galois_keys();
print_line(__LINE__);
cout << "Print the parameter IDs of generated elements." << endl;
cout << "    + public_key:  " << public_key.parms_id() << endl;
cout << "    + secret_key:  " << secret_key.parms_id() << endl;
cout << "    + relin_keys:  " << relin_keys.parms_id() << endl;
cout << "    + galois_keys: " << galois_keys.parms_id() << endl;

Encryptor encryptor(context, public_key);
Evaluator evaluator(context);
Decryptor decryptor(context, secret_key);

/*
In the BFV scheme plaintexts do not carry a parms_id, but ciphertexts do. Note
how the freshly encrypted ciphertext is at the highest data level.
*/
Plaintext plain("1x^3 + 2x^2 + 3x^1 + 4");
Ciphertext encrypted;
encryptor.encrypt(plain, encrypted);
cout << "    + plain:       " << plain.parms_id() << " (not set in BFV)" << endl;
cout << "    + encrypted:   " << encrypted.parms_id() << endl << endl;

“模切换”是一种改变密文参数的技术。函数Evaluator::mod_switch_to_next 总是切换到链的下一层,而Evaluator::mod_switch_to 切换到与给定parms_id对应的链下的参数集。但是,不可能在链中向上切换。

    print_line(__LINE__);
    cout << "Perform modulus switching on encrypted and print." << endl;
    context_data = context->first_context_data();
    cout << "---->";
    while(context_data->next_context_data())
    {
    
    
        cout << " Level (chain index): " << context_data->chain_index() << endl;
        cout << "      parms_id of encrypted: " << encrypted.parms_id() << endl;
        cout << "      Noise budget at this level: "
            << decryptor.invariant_noise_budget(encrypted) << " bits" << endl;
        cout << "\\" << endl;
        cout << " \\-->";
        evaluator.mod_switch_to_next_inplace(encrypted);
        context_data = context_data->next_context_data();
    }
    cout << " Level (chain index): " << context_data->chain_index() << endl;
    cout << "      parms_id of encrypted: " << encrypted.parms_id() << endl;
    cout << "      Noise budget at this level: "
        << decryptor.invariant_noise_budget(encrypted) << " bits" << endl;
    cout << "\\" << endl;
    cout << " \\-->";
    cout << " End of chain reached" << endl << endl;

我们可以检查模量交换链是否只针对最高的两个级别(key level和最高数据 level )创建。下面的循环应该只执行一次。

    cout << "Optionally disable modulus switching chain expansion." << endl;
    print_line(__LINE__);
    cout << "Print the modulus switching chain." << endl;
    cout << "---->";
    for (context_data = context->key_context_data(); context_data;
        context_data = context_data->next_context_data())
    {
    
    
        cout << " Level (chain index): " << context_data->chain_index() << endl;
        cout << "      parms_id: " << context_data->parms_id() << endl;
        cout << "      coeff_modulus primes: ";
        cout << hex;
        for (const auto &prime : context_data->parms().coeff_modulus())
        {
    
    
            cout << prime.value() << " ";
        }
        cout << dec << endl;
        cout << "\\" << endl;
        cout << " \\-->";
    }
    cout << " End of chain reached" << endl << endl;

猜你喜欢

转载自blog.csdn.net/weixin_46021936/article/details/122520848