文山壮族苗族自治州网站建设_网站建设公司_自助建站_seo优化
2026/1/22 15:53:54 网站建设 项目流程

Microsoft SEAL(Simple Encrypted Arithmetic Library)是微软开源的轻量级、高性能全同态加密(FHE)库,专为整数/浮点数的密文运算设计,支持BFV、CKKS、BGV等主流FHE方案,广泛应用于隐私计算、联邦学习、数据加密等场景,源码:https://github.com/microsoft/SEAL。

1 数学基础

1.1 多项式环

SEAL使用的基础环是:

image

BFV的所有运算都在这个多项式环中进行,符号含义如下:

Zq:系数域,即多项式的所有系数都取自“模q的整数集合”,q称为系数模数(一个大素数或多个素数的乘积),决定密文的噪声容忍度和运算深度。

xN+1:多项式模,要求N是2的整数幂(如4096、8192),满足xN≡-1 (mod xN+1),这意味着所有多项式的次数都不会超过N-1(超过的项可通过xN = -1降次)。

Rq元素形式:任意元素是一个次数≤ N - 1的多项式,形如:

image

 

1.2 明文空间

image

明文(待加密的整数)会被编码为Rt中的多项式,t满足t≡1 (mod 2N),这是批量加密的硬性要求,明文在进行加密前要进行编码,有两种编码方式:

单整数编码:将单个整数m编码为常数多项式f(x)=m,即所有高次项系数为0。

批量编码:将N个小整数[m0,m1,...,mN-1]直接做为多项式的系数,编码为:

image

1.3 RLWE问题

BFV的安全性基于RLWE问题(Ring Learning With Errors)的计算困难性,简单描述为:

给定多项式Rq,选择一个秘密多项式s(x)∈Rq(系数为0/1的短多项式),以及大量的“噪声多项式对”(ai(x), bi(x)),其中ai(x)是随机生成的,bi(x)=ai(x)s(x)+ei(x) (mod q)是通过秘密多项式s(x)计算得到的“响应多项式”,加入噪声ei(x)是为了让bi(x)看起来像一个完全随机的多项式,从而隐藏s(x)的存在,而在计算上无法从这些多项式对中恢复出秘密多项式s(x)。对于bi(x)其生成时每一部分的作用如下:

ai(x):从多项式环Rq中均匀随机生成的多项式,相当于“公共输入”,可以公开。

s(x):秘密多项式(系数仅为0或1),是整个RLWE问题的核心,必须严格保密。

ei(x):小系数噪声多项式(系数仅为-1、0、1),是“隐藏秘密”的关键。

bi(x):由ai(x)s(x)加上噪声得到的结果,与ai(x)一起构成公开的“多项式对”。

如果没有噪声ei(x),即ei(x)=0,那么bi(x)=ai(x)s(x) (mod q),此时攻击者可以通过多组(ai(x), bi(x))构建线性方程组,直接解密出秘密多项式s(x),这就完全失去了安全性。而加入小噪声ei(x)后:

bi(x)不再是ai(x)s(x)的精确结果,而是一个“近似值”;

这个近似值的误差被控制在很小的范围内(由ei(x)的系数大小决定);

从计算角度,目前没有任何算法(包括量子算法)能高效地从这些带噪声的近似结果中恢复出s(x),这正是RLWE问题的“计算困难性”来源,也是BFV适合后量子秘密场景的原因。

1.4 缩放因子

在BFV同态加密方案中,缩放因子(Scaling Factor)是连接明文空间(Zt)和密文空间(Zq)的核心系数,本质是为了让明文多项式能“适配”系数模数q的范围,同时保证解密时可以精确还原明文。BFV的明文模数t远小于系数模数q(t<<q),比如t=65537,q=260量级。

明文多项式m(x)∈Rt的系数范围是[0, t-1],而密文多项式c(x)∈Rq的系数范围是[0, q-1],如果直接将明文m(x)放入密文公式,由于t太小,明文信息会被噪声和掩码完全淹没,无法解密。因此需要一个缩放因子,将明文系数放大到q的量级,再参与密文计算。缩放因子贯穿加密和解密两个核心步骤,是明文和密文的“桥梁”。

(1)加密时:明文放大

在加密步骤中,明文多项式m(x)不会直接代入密文公式,而是先乘于缩放因子Δ,再放入到公式:

 

image

作用:将明文系数从[0, t-1]放大到[0, Δ*(t-1)],这个范围在q的量级内,能避免明文被噪声覆盖。

(2)解密时:明文缩小

解密的核心步骤是先计算聚合多项式D(ct),代入加密公式后可得:

image

此时需要反向缩放来还原明文:

image

概括来说,缩放因子不会直接参与运算,但会间接影响噪声的增长速度:

1) 加法运算:密文加法是系数直接相加,噪声线性叠加,缩放因子不影响噪声增长;

2) 乘法运算:密文乘法是多项式乘法,噪声会平方增长,而缩放因子Δ越大,噪声的规模也会越大,导致运算深度降低。

因此,在参数配置时,需要在“明文范围(t大小)”和“运算深度(q大小)”之间做权衡:

若t增大→Δ减小→噪声容忍度提升→运算深度增加;

若t减小→Δ增大→噪声容忍度降低→运算深度减小。

所以t与Δ成反比,需根据业务需求平衡明文范围和运算深度。

2 BFV核心流程

2.1 参数配置

参数配置决定方案的性能与安全性,BFV核心参数有4个,需严格满足数学约束:

image

参数约束:需满足q>t*(2N)d*B(d是目标运算深度,B是噪声上限),否则运算过程中噪声会“爆炸”导致解密失败。

2.2 密钥生成

基于RLWE问题生成私钥、公钥、重线性化密钥3中密钥,核心是构造含噪声的多项式对。

(1)私钥(sk)

随机生成一个短多项式s(x)∈Rq,系数仅为0或1(如s(x) = 1 + x2 + x5),私钥就是s(x)。

(2)公钥(pk)

随机生成多项式a(x)∈Rq,生成小希数噪声多项式e(x)∈Rq,计算b(x) = -a(x)s(x) + e(x) (mod q),公钥是多项式对pk = (b(x), a(x)),可公开传播。这里的噪声e(x)让攻击者无法从公钥对中恢复私钥s(x),目的是解决“公钥本身的安全性”。

(3)重线性化密钥(rlk)

密文乘法会导致密文从“2项多项式”膨胀为“3项多项式”,后续运算效率骤降。重线性化密钥用于将膨胀后的密文压缩回2项,生成逻辑与公钥类似,本质是一组扩展的RLWE多项式对。

2.3 加密

将明文多项式转为密文多项式,BFV的密文是Rq中的2项多项式对ct = (c0(x), c1(x)),加密过程分两步:

(1)明文编码:将整数明文m编码为明文多项式m(x)∈Rt

(2)添加噪声与混淆:

随机生成两个小噪声多项式e0(x),e1(x)∈Rq,随机生成一个“掩码多项式”u(x)∈Rq(系数为0/1),计算密文:

image

核心设计:密文中包含明文信息m(x),但被噪声e0/e1和掩码u(x)混淆,只有私钥能去除混淆和噪声。该步骤中的掩码多项式u(x)和噪声多项式e0(x),e1(x)是两套独立的安全机制,它们解决的是完全不同的问题,不能互相替代,如下图:

image

u(x)通过随机缩放实现公钥和明文间的非固定线性关系,噪声通过“近似”进一步打破它们之间精确的代数关系,使得攻击者无法从近似值中还原精确明文。

2.4 同态运算

这步的核心是:密文运算=多项式环运算,BFV支持秘密&密文(Ct&Ct)和密文&明文(Ct&Pt)的加减乘运算,所有运算都在多项式环Rq中进行,且无需密钥。

image

运算后的密文仍然是合法的RLWE密文,可继续参与后续运算——这就是「同态性」的体现。

2.5 解密

解密是加密的逆运算,核心是去除噪声、还原明文多项式,步骤如下:

(1)密文聚合

用私钥s(x)计算聚合多项式:

image

代入加密公式可推导:

image

(2)噪声去除

由于总噪声etotal<q/(2t),可通过“舍入+模运算”还原明文:

image(3)明文解码

将解密后的多项式m(x)转换回整数(单整数取常数项,批量加密取所有系数)。

解密成功条件:总噪声etotal<q/(2t),若运算次数过多导致噪声爆炸,舍入后无法还原明文,则会解密失败——这是BFV“层次性”的本质,运算深度有限。

 

3 SEAL使用

3.1 源码编译

这里仅简单介绍下Windows下使用VS2022环境进行编译,下载源码并安装cmake,运行VS2022安装菜单下的“Developer Command Prompt for VS 2022”命令行,执行命令进行配置:

cmake -S . -B build -G "Visual Studio 17 2022" -A x64 -DCMAKE_INSTALL_PREFIX=./out

这里编译的是64位版本,并将安装目录设置为当前目录下的out文件夹,配置完成后再执行以下命令进行编译

cmake --build build --config Release    #编译Release版本
cmake --build build --config Debug      #编译Debug版本

编译完成后会生成seal-4.1.lib库文件:

image

然后执行以下命令进行安装:

cmake --install build

out下include中是头文件,lib中是静态库文件:

image

3.2 示例程序

使用VS2022创建空项目,并添加demo.cpp文件,内容如下:

 1 #include <iostream>
 2 #include <SEAL/SEAL.h>
 3 
 4 using namespace std;
 5 using namespace seal;
 6 
 7 int main() {
 8     // 步骤 1:配置加密参数(BFV 方案)
 9     EncryptionParameters parms(scheme_type::bfv);
10     // 多项式模数:4096(2的幂次)
11     size_t poly_modulus_degree = 4096;
12     parms.set_poly_modulus_degree(poly_modulus_degree);
13     // 明文模数:支持批量运算,取值范围 2^20
14     parms.set_plain_modulus(PlainModulus::Batching(poly_modulus_degree, 20));
15     // 系数模数:使用 BFV 默认参数
16     parms.set_coeff_modulus(CoeffModulus::BFVDefault(poly_modulus_degree));
17 
18     cout << "明文模数 t = " << parms.plain_modulus().value() << endl;
19     cout << "明文模数 t 比特数 = " << parms.plain_modulus().bit_count() << endl;
20     cout << "t mod 2N = " << (parms.plain_modulus().value() % (2 * poly_modulus_degree)) << endl;
21 
22     vector<Modulus> coeff_mods = CoeffModulus::BFVDefault(poly_modulus_degree);
23 
24     // 3. 系数模数 q(多素数乘积)
25     cout << "\n系数模数 q 的构成(素数列表):" << endl;
26     int total_bits = 0;
27     for (size_t i = 0; i < coeff_mods.size(); i++) {
28         cout << "" << i + 1 << "个素数:" << coeff_mods[i].value()
29             << "(比特数:" << coeff_mods[i].bit_count() << "" << endl;
30         total_bits += coeff_mods[i].bit_count();
31     }
32     cout << "系数模数总比特数 = " << total_bits << endl;
33 
34     // 步骤 2:创建加密上下文,验证参数合法性
35     SEALContext context(parms);
36     // 打印上下文信息(可选,查看参数配置)
37     cout << "Context created successfully, scheme type: BFV" << endl;
38 
39     // 步骤 3:生成密钥(适配 SEAL 4.1 API,核心修改部分)
40     KeyGenerator keygen(context);
41     // 4.1 版本:通过 create_public_key() 生成公钥(替代原 public_key())
42     PublicKey public_key;
43     keygen.create_public_key(public_key);
44     // 4.1 版本:直接通过成员函数获取私钥(该接口未变更)
45     SecretKey secret_key = keygen.secret_key();
46     // 4.1 版本:通过 create_relin_keys() 生成评估密钥(替代原 relin_keys())
47     RelinKeys relin_keys;
48     keygen.create_relin_keys(relin_keys);
49 
50     // 步骤 4:初始化加密器、解密器、评估器
51     Encryptor encryptor(context, public_key);
52     Decryptor decryptor(context, secret_key);
53     Evaluator evaluator(context);
54 
55     // 步骤 5:明文准备(两个整数)
56     Plaintext plain1("123");
57     Plaintext plain2("456");
58     cout << "Original plaintext 1: " << plain1.to_string() << endl;
59     cout << "Original plaintext 2: " << plain2.to_string() << endl;
60 
61     // 步骤 6:加密明文为密文
62     Ciphertext cipher1, cipher2;
63     encryptor.encrypt(plain1, cipher1);
64     encryptor.encrypt(plain2, cipher2);
65     cout << "Plaintext encrypted to ciphertext successfully" << endl;
66 
67     // 步骤 7:密文同态运算(加法 + 乘法)
68     // 密文加法
69     Ciphertext cipher_add;
70     evaluator.add(cipher1, cipher2, cipher_add);
71     // 密文乘法 + 重线性化(减少密文大小)
72     Ciphertext cipher_mult;
73     evaluator.multiply(cipher1, cipher2, cipher_mult);
74     evaluator.relinearize_inplace(cipher_mult, relin_keys);
75 
76     // 步骤 8:解密密文,验证结果
77     Plaintext plain_add, plain_mult;
78     decryptor.decrypt(cipher_add, plain_add);
79     decryptor.decrypt(cipher_mult, plain_mult);
80     cout << "Ciphertext add result: " << plain_add.to_string() << endl;
81     cout << "Ciphertext multiply result: " << plain_mult.to_string() << endl;
82     
83     return 0;
84 }
View Code

将之间产生的out文件夹下的include和lib拷贝到项目文件夹下,配置项目的C/C++编译包含头文件路径,库文件路径以及输入库,即可进行编译。

image

编译完成后运行程序,输出如下:

image

在该示例程序中,多项式模数N是4096,明文模数t是1032193,位宽为20bits,系数模数q是3个素数的乘积68719403009*68719230977*137438822401=0x1ffff4400622fecd904df7f92001,位宽是109bits,示例中演示了0x123和0x456的加法和乘法运行,可见加密运算后的解密结果和未加密运算的结果完全一致。

 

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询