首页 > 其他分享 >同态加密和SEAL库的介绍(二)BFV 基础方案实现

同态加密和SEAL库的介绍(二)BFV 基础方案实现

时间:2024-08-06 15:59:56浏览次数:14  
标签:std Ciphertext const 同态 encrypted SEAL BFV 密文 plain

写在前面:
        本篇具体讲解如何使用BFV加密方案对加密的整数进行简单的计算(一个多项式评估),来源是官方提供的示例。BFV是比较常见的方案,在很多大模型推理的时候,都是将浮点数的权重和输入变换成整数后用BFV方案来实现。

一、参数的设置

        需要进行的第一个任务是设置一个EncryptionParameters类的实例。理解不同参数的行为、它们如何影响加密方案、性能以及安全级别是至关重要的。先指定方案模式:

using namespace std;
using namespace seal;

EncryptionParameters parms(scheme_type::bfv);

需要设置三个加密参数:

  •  poly_modulus_degree(多项式模数的度数)
  •  coeff_modulus([密文]系数模数)
  •  plain_modulus(明文模数,仅适用于BFV方案)

        对加密后的密文进行操作时,只能使用特定的操作(加减法和乘法),尤其是乘法要关注其深度。因为每个密文都有一个特定的量,称为`不变噪声预算`(简称`噪声预算`),以比特为单位测量。新加密的密文中的噪声预算(初始噪声预算)由加密参数决定。同态运算以由加密参数决定的速率消耗噪声预算。

        在BFV中,允许对加密数据进行的两个基本操作是加法和乘法,其中相比于乘法,加法在噪声预算消耗方面几乎可以认为是免费的。由于噪声预算在连续乘法中会累积消耗,选择适当的加密参数的最重要因素是用户想要在加密数据上评估的算术电路的乘法深度。

        一旦密文的噪声预算达到零,它就会变得过于损坏而无法解密。因此,必须选择足够大的参数以支持所需的计算(过大会影响性能);否则,即使使用密钥也无法理解结果。

1.1 poly_modulus_degree

        第一个参数是`多项式模数`的度数。这必须是2的正幂,代表2幂次的循环多项式的度数;
较大的poly_modulus_degree会使密文尺寸变大且所有操作变慢,但能进行更复杂的加密计算。推荐的值是1024、2048、4096、8192、16384、32768,但也可以超出这个范围。

size_t poly_modulus_degree = 4096;
parms.set_poly_modulus_degree(poly_modulus_degree);

1.2 coeff_modulus

        接下来设置[密文]`系数模数`(coeff_modulus)。该参数是一个大整数,是不同素数的乘积,每个素数最多为60位。它表示为这些素数组成的向量,每个素数由Modulus类的一个实例表示。coeff_modulus的位长度意味着其素数因子位长度的总和。

        较大的coeff_modulus意味着较大的噪声预算,因此有更多的加密计算能力。然而,coeff_modulus的总位长度上限由poly_modulus_degree决定:

poly_modulus_degreemax coeff_modulus bit-length
102427
204854
4096109
8192218
16384438
32768881

        这些数字也可以在native/src/seal/util/hestdparms.h中找到,编码在函数SEAL_HE_STD_PARMS_128_TC中,也可以通过函数CoeffModulus::MaxBitCount(poly_modulus_degree)获得。

        例如,如果poly_modulus_degree为4096,coeff_modulus可以由三个36位的素数组成(108位)。

        SEAL提供了选择coeff_modulus的辅助函数。对于新用户,最简单的方法是直接使用CoeffModulus::BFVDefault(poly_modulus_degree),它返回一个std::vector<Modulus>,其中包含对于给定poly_modulus_degree通常较好的选择。

parms.set_coeff_modulus(CoeffModulus::BFVDefault(poly_modulus_degree));

1.3 plain_modulus

        明文模数可以是任何正整数,尽管这里我们将其设为2的幂。事实上,在很多情况下,可能希望它是一个素数;明文模数决定了明文数据类型的大小以及乘法中噪声预算的消耗。因此,为了获得最佳性能,必须尽量保持明文数据类型尽可能小。明文模数是BFV方案特有的,使用CKKS方案时不能设置。
        新加密密文中的噪声预算为:log2(coeff_modulus/plain_modulus)(比特)
        同态乘法中的噪声预算消耗形式为log2(plain_modulus) + (其他项)。

parms.set_plain_modulus(1024);

所有参数都设置好了,构建一个SEALContext对象,Microsoft SEAL将首先验证这些参数。

SEALContext context(parms);

官方例子中,打印了这个校验结果:
 

f41b38b04c0746608a7913c9c347a1ee.png

二、加解密

        Microsoft SEAL中的加密方案是公钥加密方案。这样,多个方可以使用同一个共享公钥加密数据,但只有数据的正确接收者才能使用密钥解密。

        生成密钥和公钥,我们需要一个KeyGenerator类的实例。构建一个KeyGenerator会自动生成一个密钥。然后,我们可以使用KeyGenerator::create_public_key为其创建任意多的公钥。注意,KeyGenerator::create_public_key还有一个不带参数的重载,返回一个Serializable<PublicKey>对象。

KeyGenerator keygen(context);
SecretKey secret_key = keygen.secret_key();
PublicKey public_key;
keygen.create_public_key(public_key);
// 为了能够加密,需要构建Encryptor实例。
// Encryptor只需要公钥
Encryptor encryptor(context, public_key);

对密文的计算是通过Evaluator类进行的。在实际使用中,Evaluator不会由持有密钥的一方构建。

Evaluator evaluator(context);

解密以验证一切正常,所以我们还需要构建一个Decryptor实例。注意,Decryptor需要密钥。

Decryptor decryptor(context, secret_key);

三、多项式运算

        示例中的运算是评估评4次多项式,输入是加密的x = 6,多项式的系数可以看作是明文输入:

   eq?4x%5E4%20&plus;%208x%5E3%20&plus;%208x%5E2%20&plus;%208x%20&plus;%204

        在BFV方案中,明文是度小于多项式模数的多项式,系数是模明文模数的整数。对于有环理论背景的读者来说,明文空间是多项式商环Z_T[X]/(X^N + 1),其中N是poly_modulus_degree,T是plain_modulus。

3.1 对输入进行编码和加密

        这里编码是说把输入的变量(当然向量也可以,下面在batch_encoder会介绍),编码成Plaintext对象,然后再加密成Ciphertext对象。这里用的构造函数将多项式作为字符串,系数表示为十六进制数

uint64_t x = 6;
Plaintext x_plain(uint64_to_hex_string(x));

Ciphertext x_encrypted;
encryptor.encrypt(x_plain, x_encrypted);

        在Microsoft SEAL中,一个有效的密文由两个或更多个多项式组成,其系数是模coeff_modulus中素数乘积的整数。密文中的多项式数量称为它的“大小”,由Ciphertext::size()给出,新加密的密文总是大小为2。
        这里可以直接打印查看其刚加密时的噪声预算:

cout << "    + noise budget in freshly encrypted x: " << decryptor.invariant_noise_budget(x_encrypted) << " bits" << endl;

示例这里打印结果是:

c30dc4c2604644c28a1b1185836e9d01.png

3.2 运算

        使用Microsoft SEAL时,通常有利于以最小化最长连续乘法链的方式进行计算。换句话说,最好的加密计算评估方式是最小化计算的乘法深度,因为总噪声预算消耗与乘法深度成正比。

        故这里对上面的多项式计算进行因式分解,以获得一个简单的深度2的表示是有利的。

eq?4x%5E4%20&plus;%208x%5E3%20&plus;%208x%5E2%20&plus;%208x%20&plus;%204%20%3D%204%28x%20&plus;%201%29%5E2%20*%20%28x%5E2%20&plus;%201%29

因此,我们分别计算  eq?%28x%20&plus;%201%29%5E2 和  eq?%28x%5E2%20&plus;%201%29 ,然后再乘以4即可。


首先,我们计算x^2并加上一个明文“1”:

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

        加密乘法导致输出密文的大小增加。更确切地说,如果输入密文的大小为M和N,则同态乘法后的输出密文大小为M+N-1。我们先察密文大小的增长和噪声预算的消耗:

cout << " + size of x_sq_plus_one: " << x_sq_plus_one.size() << endl;
cout << " + noise budget in x_sq_plus_one: " << decryptor.invariant_noise_budget(x_sq_plus_one) << " bits" << endl;

示例中输出如下(这里示例还进行了解密,加以验证中间结果,注意是十六进制):

d377c41901ad49d7a2a16a7c5b012ebf.png

        通过输出可以发现,乘法消耗了大量的噪声预算,并且增加了密文长度。但是解密可以发现,尽管大小增加了,只要噪声预算没有达到0,解密仍然可以正常工作


接下来,我们计算  eq?%28x%20&plus;%201%29%5E2

Ciphertext x_plus_one_sq;
evaluator.add_plain(x_encrypted, plain_one, x_plus_one_sq);
evaluator.square_inplace(x_plus_one_sq);

        注意这里是用的 x_encrypted ,区分上面的中间结果 x_sq_plus_one,即噪声消耗也是针对初始的 55bit,这里对密文长度和噪声进行输出,并解密验证(注意是十六进制):

d2eb76f63f174ceb8c2a581fcbcafcd0.png


最后,我们计算  eq?%28x%5E2%20&plus;%201%29%20*%20%28x%20&plus;%201%29%5E2%20*%204 :

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

        注:这里调用的两个乘法不一样,因为明文乘密文和密文乘密文是不一样的,前者时间更短,下面会具体讲这几个运算的函数。照上例对乘法结果的情况进行输出:

fbaaba96b1ed4e8caf21afbe7dcb2db4.png

        如果噪声预算达到0,这意味着解密无法得到正确的结果。这是因为密文 x_sq_plus_one 和 x_plus_one_sq 由于之前的平方运算都包含3个多项式,并且对大密文的同态操作比对小密文的计算消耗更多的噪声预算,对较小的密文进行计算在计算上也明显更便宜


3.3 重新线性化

        Relinearization - 重新线性化 是一种将乘法后的密文大小减少回初始大小2的操作。因此,在下一次乘法前对一个或两个输入密文进行重新线性化,即使重新线性化本身具有显著的计算成本,也可以对噪声增长和性能产生巨大的正面影响。重新线性化只能将大小3的密文减少到大小2,所以通常用户会在每次乘法后重新线性化以保持密文大小为2。

        重新线性化需要特殊的`RelinKeys',可以将其视为一种公钥。重新线性化密钥可以通过KeyGenerator轻松创建:

RelinKeys relin_keys;
keygen.create_relin_keys(relin_keys);

        重新线性化在 BFV 和 CKKS 方案中使用类似,但在这个例子中我们继续使用BFV。我们重复之前的计算,但这次在每次乘法后进行重新线性化:

Ciphertext x_squared;
evaluator.square(x_encrypted, x_squared);
evaluator.relinearize_inplace(x_squared, relin_keys);
evaluator.add_plain(x_squared, plain_one, x_sq_plus_one);

Ciphertext x_plus_one;
evaluator.add_plain(x_encrypted, plain_one, x_plus_one);
evaluator.square(x_plus_one, x_plus_one_sq);
evaluator.relinearize_inplace(x_plus_one_sq, relin_keys);

evaluator.multiply_plain_inplace(x_sq_plus_one, plain_four);
evaluator.multiply(x_sq_plus_one, x_plus_one_sq, encrypted_result);
evaluator.relinearize_inplace(encrypted_result, relin_keys);

像之前一样,打印中间结果可以看到:

8425b8c6900b40a4a7ad880a23e4e29b.png

        可以看出来,每次乘完的重新线性化让多项式长度减少,避免了两个长度为三的密文相乘,改善了噪声的消耗。这样还有噪声剩余,可以进行其他进一步运算。当然,需要注意,如果像示例中这样,运算只进行到此,即没有更深的乘法深度,即噪声预算已经够用。但是重新线性化会带来额外的时间开销,故就不一定需要了,按情况而定。

3.4 结果解密

decryptor.decrypt(encrypted_result, decrypted_result);
cout << "    + decryption of 4(x^2+1)(x+1)^2 = 0x" << decrypted_result.to_string() << " ...... Correct." << endl;

打印如下:

634af6dd1b614029b86d6eca38fd2d5c.png

        但是需要注意一点,对于x=6,4(x^2+1)(x+1)^2 = 7252,由于明文模数设置为1024,这个结果是在整数模 1024 下计算的。因此,预期输出应该是7252 % 1024 == 84,或者十六进制表示为0x54。

        因此明文模数设置的小了,就不能还原计算结果;但是太大了,计算速度就比较慢,故最好计算之前进行一定的评估,设置合理的参数。


        有时我们创建的自定义加密参数会变得无效。比如这里我们简单地减少多项式模数度数,使参数不符合HomomorphicEncryption.org的安全标准,这些信息有助于修复无效的加密参数。

parms.set_poly_modulus_degree(2048);
context = SEALContext(parms);
print_parameters(context);
cout << "Parameter validation (failed): " << context.parameter_error_message();

3301098b9b524954916da29f908cd2bf.png

四、运算函数

        这里简单介绍上面所用到的几个运算的函数,方便大家更好的使用,这些都可以在 evaluator.h 里面找到。当然,这些运算是不挑模式的,即BFV和CKKS都可以直接使用。因为内容过多,所以相似的部分就会省略。

        首先来看看内存, 可以打印我们从当前内存池中分配了多少内存。默认情况下,内存池将是一个静态全局池,可以使用MemoryManager类来更改它。 大多数用户几乎没有理由修改内存分配系统。

size_t megabytes = MemoryManager::GetPool().alloc_byte_count() >> 20;
cout << "[" << setw(7) << right << megabytes << " MB] "
     << "Total allocation from the memory pool" << endl;

4.1 加法

 void add_inplace(Ciphertext &encrypted1, const Ciphertext &encrypted2)
  • 功能:这个函数用于将两个密文相加。它将 encrypted1encrypted2 相加,并将结果存储在 encrypted1 中。
  • 参数
    • encrypted1:第一个要相加的密文。
    • encrypted2:第二个要相加的密文。
  • 异常
    • std::invalid_argument:如果 encrypted1encrypted2 对加密参数无效,则抛出此异常。
    • std::invalid_argument:如果 encrypted1encrypted2 处于不同的NTT形式(Number Theoretic Transform形式),则抛出此异常。
    • std::invalid_argument:如果 encrypted1encrypted2 处于不同的级别或尺度,则抛出此异常。
    • std::logic_error:如果结果密文是透明的,则抛出此异常。
inline void add(const Ciphertext &encrypted1, const Ciphertext &encrypted2, Ciphertext &destination)
  • 功能:这个函数用于将两个密文相加。它将 encrypted1encrypted2 相加,并将结果存储在 destination 参数中。
  • 参数
    • encrypted1:第一个要相加的密文。
    • encrypted2:第二个要相加的密文。
    • destination:要用加法结果覆盖的密文。
void add_many(const std::vector<Ciphertext> &encrypteds, Ciphertext &destination) const;
  • 功能:这个函数用于将一个密文向量中的所有密文相加,并将结果存储在 destination 参数中。
  • 参数
    • encrypteds:要相加的密文向量。
    • destination:要用加法结果覆盖的密文。
  • 异常
    • std::invalid_argument:如果 encrypteds 为空,则抛出此异常。
    • std::invalid_argument:如果 encrypteds 中的密文对加密参数无效,则抛出此异常。
    • std::invalid_argument:如果 encrypteds 中的密文处于不同的NTT形式,则抛出此异常。
    • std::invalid_argument:如果 encrypteds 中的密文处于不同的级别或尺度,则抛出此异常。
    • std::invalid_argument:如果 destinationencrypteds 中的一个密文,则抛出此异常。
    • std::logic_error:如果结果密文是透明的,则抛出此异常。

同理还有加明文的:

void add_plain_inplace(
    Ciphertext &encrypted, const Plaintext &plain, MemoryPoolHandle pool = MemoryManager::GetPool()) const;
inline void add_plain(
    const Ciphertext &encrypted, const Plaintext &plain, Ciphertext &destination,
    MemoryPoolHandle pool = MemoryManager::GetPool()) const

4.2 减法

void sub_inplace(Ciphertext &encrypted1, const Ciphertext &encrypted2) const;
  • 功能:这个函数用于将两个密文相减。它计算 encrypted1encrypted2 的差,并将结果存储在 encrypted1 中。
  • 参数
    • encrypted1:要被减的密文。
    • encrypted2:要减去的密文。
  • 异常
    • std::invalid_argument:如果 encrypted1encrypted2 对加密参数无效,则抛出此异常。
    • std::invalid_argument:如果 encrypted1encrypted2 处于不同的NTT形式,则抛出此异常。
    • std::invalid_argument:如果 encrypted1encrypted2 处于不同的级别或尺度,则抛出此异常。
    • std::logic_error:如果结果密文是透明的,则抛出此异常。
inline void sub(const Ciphertext &encrypted1, const Ciphertext &encrypted2, Ciphertext &destination) const
  • 功能:这个函数用于将两个密文相减。它计算 encrypted1encrypted2 的差,并将结果存储在 destination 参数中。
  • 参数
    • encrypted1:要被减的密文。
    • encrypted2:要减去的密文。
    • destination:要用减法结果覆盖的密文。
void sub_plain_inplace(
    Ciphertext &encrypted, const Plaintext &plain, MemoryPoolHandle pool = MemoryManager::GetPool()) const;
inline void sub_plain(
    const Ciphertext &encrypted, const Plaintext &plain, Ciphertext &destination,
    MemoryPoolHandle pool = MemoryManager::GetPool()) const

4.3 乘法

void multiply_inplace(
    Ciphertext &encrypted1, const Ciphertext &encrypted2,
    MemoryPoolHandle pool = MemoryManager::GetPool()) const;
  • 功能:这个函数用于将两个密文相乘。它计算 encrypted1encrypted2 的乘积,并将结果存储在 encrypted1 中。在这个过程中,动态内存分配从给定的 MemoryPoolHandle 指向的内存池中分配。
  • 参数
    • encrypted1:第一个要相乘的密文。
    • encrypted2:第二个要相乘的密文。
    • pool:指向有效内存池的 MemoryPoolHandle。(一般忽略)
  • 异常
    • std::invalid_argument:如果 encrypted1encrypted2 对加密参数无效,则抛出此异常。
    • std::invalid_argument:如果 encrypted1encrypted2 不处于默认的NTT形式,则抛出此异常。
    • std::invalid_argument:如果 encrypted1encrypted2 处于不同的级别,则抛出此异常。
    • std::invalid_argument:如果输出尺度对加密参数来说太大,则抛出此异常。
    • std::invalid_argument:如果 pool 未初始化,则抛出此异常。
    • std::logic_error:如果结果密文是透明的,则抛出此异常。
inline void multiply(
    const Ciphertext &encrypted1, const Ciphertext &encrypted2, Ciphertext &destination,
    MemoryPoolHandle pool = MemoryManager::GetPool()) const
  • 功能:这个函数用于将两个密文相乘。它计算 encrypted1encrypted2 的乘积,并将结果存储在 destination 参数中。在这个过程中,动态内存分配从给定的 MemoryPoolHandle 指向的内存池中分配。
  • 参数
    • encrypted1:第一个要相乘的密文。
    • encrypted2:第二个要相乘的密文。
    • destination:要用乘法结果覆盖的密文。
    • pool:指向有效内存池的 MemoryPoolHandle
 void multiply_plain_inplace(
     Ciphertext &encrypted, const Plaintext &plain, MemoryPoolHandle pool = MemoryManager::GetPool()) const;
 inline void multiply_plain(
     const Ciphertext &encrypted, const Plaintext &plain, Ciphertext &destination,
     MemoryPoolHandle pool = MemoryManager::GetPool()) const

4.4 平方

void square_inplace(Ciphertext &encrypted, MemoryPoolHandle pool = MemoryManager::GetPool()) const;
  • 功能:这个函数用于对一个密文进行平方运算。它计算 encrypted 的平方。在这个过程中,动态内存分配从给定的 MemoryPoolHandle 指向的内存池中分配。
  • 参数
    • encrypted:要进行平方运算的密文。
    • pool:指向有效内存池的 MemoryPoolHandle
  • 异常
    • std::invalid_argument:如果 encrypted 对加密参数无效,则抛出此异常。
    • std::invalid_argument:如果 encrypted 不处于默认的NTT形式,则抛出此异常。
    • std::invalid_argument:如果输出尺度对加密参数来说太大,则抛出此异常。
    • std::invalid_argument:如果 pool 未初始化,则抛出此异常。
    • std::logic_error:如果结果密文是透明的,则抛出此异常。
inline void square(
    const Ciphertext &encrypted, Ciphertext &destination,
    MemoryPoolHandle pool = MemoryManager::GetPool()) const
  • 功能:这个函数用于对一个密文进行平方运算。它计算 encrypted 的平方,并将结果存储在 destination 参数中。在这个过程中,动态内存分配从给定的 MemoryPoolHandle 指向的内存池中分配。
  • 参数
    • encrypted:要进行平方运算的密文。
    • destination:要用平方结果覆盖的密文。

4.5 重新线性化

inline void relinearize_inplace(
    Ciphertext &encrypted, const RelinKeys &relin_keys, MemoryPoolHandle pool = MemoryManager::GetPool()) const
  • 功能:这个函数用于对一个密文进行重线性化操作,减少其大小至2。如果密文的大小为K+1,则给定的重线性化密钥的大小至少需要为K-1。在这个过程中,动态内存分配从给定的 MemoryPoolHandle 指向的内存池中分配。
  • 参数
    • encrypted:要进行重线性化的密文。
    • relin_keys:重线性化密钥。
    • pool:指向有效内存池的 MemoryPoolHandle
  • 异常
    • std::invalid_argument:如果 encryptedrelin_keys 对加密参数无效,则抛出此异常。
    • std::invalid_argument:如果 encrypted 不处于默认的NTT形式,则抛出此异常。
    • std::invalid_argument:如果 relin_keys 不对应当前上下文中的顶级参数,则抛出此异常。
    • std::invalid_argument:如果 relin_keys 的大小太小,则抛出此异常。
    • std::invalid_argument:如果 pool 未初始化,则抛出此异常。
    • std::logic_error:如果上下文不支持密钥切换,则抛出此异常。
    • std::logic_error:如果结果密文是透明的,则抛出此异常。
inline void relinearize(
    const Ciphertext &encrypted, const RelinKeys &relin_keys, Ciphertext &destination,
    MemoryPoolHandle pool = MemoryManager::GetPool()) const;

4.6 幂运算

void exponentiate_inplace(
    Ciphertext &encrypted, std::uint64_t exponent, const RelinKeys &relin_keys,
    MemoryPoolHandle pool = MemoryManager::GetPool()) const;
  • 功能:这个函数用于对一个密文进行幂运算,将 encrypted 提升到 exponent 次幂。在计算过程中,动态内存分配从给定的 MemoryPoolHandle 指向的内存池中分配。幂运算以深度优化的顺序完成,并在每次乘法后自动进行重线性化,使用给定的重线性化密钥。
  • 参数
    • encrypted:要进行幂运算的密文。
    • exponent:密文要提升的幂次。
    • relin_keys:重线性化密钥。
    • pool:指向有效内存池的 MemoryPoolHandle
  • 异常
    • std::logic_error:如果加密方案不是 scheme_type::bfvscheme_type::bgv,则抛出此异常。
    • std::invalid_argument:如果 encryptedrelin_keys 对加密参数无效,则抛出此异常。
    • std::invalid_argument:如果 encrypted 不处于默认的NTT形式,则抛出此异常。
    • std::invalid_argument:如果输出尺度对加密参数来说太大,则抛出此异常。
    • std::invalid_argument:如果 exponent 为零,则抛出此异常。
    • std::invalid_argument:如果 relin_keys 的大小太小,则抛出此异常。
    • std::invalid_argument:如果 pool 未初始化,则抛出此异常。
    • std::logic_error:如果上下文不支持密钥切换,则抛出此异常。
    • std::logic_error:如果结果密文是透明的,则抛出此异常。
inline void exponentiate(
    const Ciphertext &encrypted, std::uint64_t exponent, const RelinKeys &relin_keys, Ciphertext &destination,
    MemoryPoolHandle pool = MemoryManager::GetPool()) const

4.7 其余

还有一部分因为此处没涉及到,所以就不展开介绍了,后面解释到对应部分会再补充。包括了:

  1. rotate_rows_inplace
  2. rotate_columns_inplace
  3. mod_switch_to_inplace
  4. rescale_to_inplace
  5. mod_reduce_to_inplace

五、结语

        在上面的例子中,我们仅使用了明文多项式的一个系数。这实际上是非常浪费的,因为明文多项式很大,而且无论如何都会被整体加密。同时,因为是取模故会产生溢出,如果直接增加 plain_modulus 参数,直到没有溢出发生,并且计算表现得像整数运算。问题在于增加 plain_modulus 会增加噪声预算的消耗,并且还会减少初始噪声预算。

        在下篇将讨论其他将数据布局到明文元素(编码)的方法,这些方法可以允许更多的计算而不会发生数据类型溢出,并且可以充分利用整个明文多项式。

 

标签:std,Ciphertext,const,同态,encrypted,SEAL,BFV,密文,plain
From: https://blog.csdn.net/WaitMrAnt/article/details/140928151

相关文章

  • Sealed with a kiss
    Thoughwe'vegottosaygoodbye即使我们必须说再见Forthesummer在这个夏天Darling,Ipromiseyouthis亲爱的,我向你承诺I'llsendyouallmylove我会对你付出我所有的爱Everydayinaletter在每天的一封信里Sealedwithakiss以吻封缄Yes,it'sgonnabe......
  • ES6 Object.freeze()和Object.seal()
    在JavaScript编程中,管理对象的可变性对于保持代码的稳定性和可预测性至关重要。有两个强大的方法可以帮助控制对象属性的变化,它们分别是Object.freeze()和Object.seal()。这篇文章将深入探讨Object.freeze()和Object.seal()的实际用途,并通过实例来说明它们的功能和使用场景,帮助......
  • 深入理解 Java17 新特性:Sealed Classes
    0关键总结JavaSE15在2020年9月发布,预览功能引入“封闭类”(JEP360)封闭类是一种限制哪些其他类或接口可扩展它的类或接口类似枚举,封闭类在领域模型中捕获替代方案,允许程序员和编译器推理其穷尽性封闭类对于创建安全的层次结构也很有用,通过解耦可访问性和可扩展性,允许库开......
  • 一篇了解Microsoft SEAL
    目录引言核心概念同态加密微软SEAL入门可选依赖项示例使用EVA进行CKKS编程手动构建MicrosoftSEAL构建C++组件要求构建微软SEAL安装微软SEAL在Windows上构建和安装(不做重点介绍)为Android和iOS构建(不做重点介绍)为WebAssembly构建(不做重点介绍)基本CMake选......
  • k8s集群-sealos快速部署
    下载sealos工具官方文档页面https://sealos.run/docs/self-hosting/lifecycle-management/quick-start/install-cliwgethttps://github.com/labring/sealos/releases/download/v4.3.7/sealos_4.3.7_linux_amd64.tar.gz部署1、配置好ssh免密后进行部署2、国内机器需要添加如......
  • 同态加密为什么被称为密码学的圣杯?
    同态加密是一种支持数据密态处理的密码学技术,可以广泛应用于云计算、医疗、金融等领域。1.什么是同态加密?全同态加密是一种加密技术,允许在不解密的前提下,对密文进行一些有意义的运算,使得解密后的结果与在明文上做“相同计算”得到的结果相同。同态加密被称为密码学的圣杯,原......
  • Sealos 5.0 正式发布,云本应该是操作系统
    把所有资源抽象成一个整体,一切皆应用,这才是云应该有的样子。2018年8月15日Sealos提交了第一行代码。随后开源社区以每年翻倍的速度高速增长。2022年我们正式创业,经历一年的研发,在2023年6月正式上线Sealos公有云版本。到目前为止,我们已经上线近一年,服务十多万用......
  • Seal-Report是一个基于.NET框架的开源报表项目
    01项目简介Seal-Report是一个基于.NET框架的开源项目,提供了简单、直观的报表和报告功能,具有报表设计器,可减少复杂的配置,无需编程知识也可以使用。采用该项目,就可以为企业快速提供高质量的报表,从而提升工作效率和决策速度。 https://github.com/ariacom/Seal-Report02项目功......
  • 零知识证明与同态加密:隐私计算的双剑
    PrimiHub一款由密码学专家团队打造的开源隐私计算平台,专注于分享数据安全、密码学、联邦学习、同态加密等隐私计算领域的技术和内容。在数字时代,隐私保护已成为全球关注的焦点。隐私计算作为解决数据隐私问题的关键技术,其核心目标是在不泄露个人或敏感信息的前提下,实现数据的计......
  • Sealos 云主机正式上线,便宜,便宜,便宜!
    我们基于Sealos云开发的能力,仅用三天时间就上线Sealos的云主机能力,现在不太懂容器的同学也可以在Sealos上开心的使用虚拟机了,本文先说Sealos云主机的优势,再聊聊我们是怎么这么快实现上线的,以及为什么我们要做这件事。目前只有广州可用区(腾讯云)上线了云主机能力,其他可用......