SEAL库的安装(Windows VS2019环境下)
笔者的话:关于SEAL的安装,在3.6版本发布后发生了一个重大的转变,自3.6版本开始,SEAL库不再提供Windows的Visual Studio解决方案文件,就是比前几个项目少了个SEAL.sln文件,这意味着,安装新版本的SEAL库就只能使用CMAKE了,老版本的SEAL库依然是可以用SEAL.sln文件来安装的,笔者按照官方文档尝试着按照了一下3.6版本的seal库,但是安装完成后无法正常通过VS调用该库(提示说是有一个关于gsl库的头文件无法正常调用,我尝试安装了完整的gsl库,但是也依然无法使用,猜测可能是SEAL库为该第三方库配置了新的内容文件,导致必须引用SEAL里带有的gsl,但是SEAL里的gsl又由于未知原因无法被编译器正常识别到),网上目前也未能找到VS相关的安装3.6版本SEAL库的说明,因此只能写一篇3.5.9版本的安装方法了。
SEAL库是一个用C++编写的,实现了全同态加密的CKKS方案和BFV方案的全同态加密库,由Microsoft在Github开源。你可以访问: https://github.com/microsoft/SEAL进入SEAL库的开源地址,更深入地了解SEAL库,本文只做简单的介绍。
SEAL库提供了密文的加减乘除等基本运算功能,还有私钥公钥的生成方法,简单而易于使用,同时,它没有其他依赖,你可以轻松地在Windows,Linux、macOS以及最新添加的Android和ios上安装并使用SEAL库。本文会对于SEAL库在Windows环境下,Visual Studio2019上的安装和配置展开详细的讲解。本文中的部分内容引用自SEAL库在github开源地址上提供的官方说明,以及微软在youtube上发布的SEAL库安装视频(从SEAL3.6.0版本开始,SEAL库取消了对于VS的sln支持文件,因此该视频提供的方案只能用于3.5版本及以前的SEAL安装),敬请见谅。
废话不多说了,下面开始正文的讲解:
-
首先,SEAL库是一个C++的库,您需要为您的VS安装好C++的编译运行环境,笔者选择安装的是如图的两项内容配置,可供您参考:
-
前往SEAL在GitHub的开源地址下载库文件:
点击左侧master选择以前的版本号:
点击右侧绿色的Code按钮,再点击最下方的Download Zip即可。
3. 下载完成后解压即可。笔者选择了解压到D盘。
需要注意的是,请务必将文件解压到SEAL文件夹下(自己新建一个叫SEAL的文件夹),否则下面的安装过程有可能报错。(我的文件夹里面有个demo文件是新建的一个测试项目,下面会讲到,不用管它没事)
-
进入你解压的文件夹中,打开seal.sln文件,这是vs专有的解决方案文件。
-
右键SEAL设置SEAL为启动项目
-
设置上方为release和64位模式
然后点击右侧的绿色三角标志的按钮,运行项目。
待运行完成,可以在输出中看到seal.lib文件的生成路径:
D:\SEAL\SEAL-3.5.9\lib\x64\Release\seal.lib
-
下面开始为项目配置SEAL库,新建一个C++的控制台项目:
右键项目,选择属性 C/C++、常规,添加附加包含目录: 目录为您的SEAL库的native文件夹下的src文件夹
而后选择链接器、常规,添加 附加库目录: 目录地址为您的SEAL文件夹下的lib文件夹,并在末尾加上后缀:\$(Platform)\$(Configuration)
用来帮助编译器找到之前生成的.lib文件。
最后,在 链接器、输入 的 附加依赖项中添加 seal.lib ,别忘了加分号和其他的库文件名分隔开。 -
之后,想要在该项目中调用seal库,只需要在程序中加上如下两句即可:
#include"seal/seal.h"
using namespace seal;
这里提供一个BFV方案的加密计算例子供您参考:
#include <cstddef>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <vector>
#include <string>
#include <chrono>
#include <random>
#include <thread>
#include <mutex>
#include <memory>
#include <limits>
#include <algorithm>
#include <numeric>
#include "seal/seal.h"
#include <time.h>
#include <math.h>
#include <cstdlib>
#include <ctime>
using namespace std;
using namespace seal;
inline void print_parameters(std::shared_ptr<seal::SEALContext> context)
{
// Verify parameters
if (!context)
{
throw std::invalid_argument("context is not set");
}
auto& context_data = *context->key_context_data();
/*
Which scheme are we using?
*/
std::string scheme_name;
switch (context_data.parms().scheme())
{
case seal::scheme_type::BFV:
scheme_name = "BFV";
break;
case seal::scheme_type::CKKS:
scheme_name = "CKKS";
break;
default:
throw std::invalid_argument("unsupported scheme");
}
std::cout << "/" << std::endl;
std::cout << "| Encryption parameters :" << std::endl;
std::cout << "| scheme: " << scheme_name << std::endl;
std::cout << "| poly_modulus_degree: " <<
context_data.parms().poly_modulus_degree() << std::endl;
/*
Print the size of the true (product) coefficient modulus.
*/
std::cout << "| coeff_modulus size: ";
std::cout << context_data.total_coeff_modulus_bit_count() << " (";
auto coeff_modulus = context_data.parms().coeff_modulus();
std::size_t coeff_mod_count = coeff_modulus.size();
for (std::size_t i = 0; i < coeff_mod_count - 1; i++)
{
std::cout << coeff_modulus[i].bit_count() << " + ";
}
std::cout << coeff_modulus.back().bit_count();
std::cout << ") bits" << std::endl;
/*
For the BFV scheme print the plain_modulus parameter.
*/
if (context_data.parms().scheme() == seal::scheme_type::BFV)
{
std::cout << "| plain_modulus: " << context_data.
parms().plain_modulus().value() << std::endl;
}
std::cout << "\\" << std::endl;
}
/*计算5*6*8*120+500+300*/
int main()
{
/* 首先设置加密方案的参数 poly_modulus 、coeff_modulus 、plain_modulus*/
EncryptionParameters parms(scheme_type::BFV);
size_t poly_modulus_degree = 4096;
parms.set_poly_modulus_degree(poly_modulus_degree);
parms.set_coeff_modulus(CoeffModulus::BFVDefault(poly_modulus_degree));
parms.set_plain_modulus(1024);
auto context = SEALContext::Create(parms);//产生context
print_parameters(context);
cout << endl;
//产生密钥、加密、解密、evaluator
KeyGenerator keygen(context);
PublicKey public_key = keygen.public_key();
SecretKey secret_key = keygen.secret_key();
RelinKeys relin_keys = keygen.relin_keys_local();
Encryptor encryptor(context, public_key);//加密机
Evaluator evaluator(context);// 评估机
Decryptor decryptor(context, secret_key);//解密机
IntegerEncoder encoder(context);//对整数编码
//5*6
int x5 = 5;
int x6 = 6;
Plaintext x5_plain;
Plaintext x6_plain;
encoder.encode(x5, x5_plain);//将整数编码
encoder.encode(x6, x6_plain);
Ciphertext x5_encrypted, x6_encrypted;//密文
encryptor.encrypt(x5_plain, x5_encrypted);
encryptor.encrypt(x6_plain, x6_encrypted);//明文加密为密文
Ciphertext x5x6_encrypted;//5*6的密文结果
evaluator.multiply(x5_encrypted, x6_encrypted, x5x6_encrypted);//密文5*6保存到x5x6-encrypted中
evaluator.relinearize_inplace(x5x6_encrypted, relin_keys);
cout << "Noise budget of x5x6_encrypted:" << decryptor.invariant_noise_budget(x5x6_encrypted) << "bits" << endl;
//对密文结果再线性化并计算噪音大小
//8*120
int x8 = 8, x120 = 120;
Plaintext x8_plain;
Plaintext x120_plain;//明文
encoder.encode(x8, x8_plain);
encoder.encode(x120, x120_plain);//转化为明文
Ciphertext x8_encrypted, x120_encrypted;//密文
encryptor.encrypt(x8_plain, x8_encrypted);
encryptor.encrypt(x120_plain, x120_encrypted);//转化为密文
Ciphertext x8x120_encrypted;//8*120结果
evaluator.multiply(x8_encrypted, x120_encrypted, x8x120_encrypted);//8*120
evaluator.relinearize_inplace(x8x120_encrypted, relin_keys);//再线性化
cout << "Noise budget of x8x120_encrypted:" << decryptor.invariant_noise_budget(x8x120_encrypted) << "bits" << endl;
//计算(5*6)*(8*120)
Ciphertext total_mul;
evaluator.multiply(x5x6_encrypted, x8x120_encrypted, total_mul);
evaluator.relinearize_inplace(total_mul, relin_keys);//再线性化
cout << "Noise budget of total_mul:" << decryptor.invariant_noise_budget(total_mul) << "bits" << endl;
//计算500+300
int x500 = 500, x300 = 300;
Plaintext x500_plain;
Plaintext x300_plain;
encoder.encode(x500, x500_plain);
encoder.encode(x300, x300_plain);
Ciphertext x500_encrypted, x300_encrypted;
encryptor.encrypt(x500_plain, x500_encrypted);
encryptor.encrypt(x300_plain, x300_encrypted);
Ciphertext total_add;
evaluator.add(x500_encrypted, x300_encrypted, total_add);//add函数相加
//计算最终结果
Ciphertext total;
evaluator.add(total_mul, total_add, total);
//解密
Plaintext result;
decryptor.decrypt(total, result);
//运用decode_int32()函数解码
cout << encoder.decode_int32(result) << endl;
}
运行结果如下: