同态加密库OpenFHE之可主动输入计算代码详解

2 篇文章 0 订阅
2 篇文章 0 订阅

0 简介

        之前做过OpenFHE里面测试用例的详解,虽然能通过调用内置的测试用例进行简单的同态运算演示,但我认为并不直观,只是输出了一些已经规定好的数值。于是我想到了另外一个办法---开放输入口,让用户输入想要进行计算的数值,然后经过同态运算后解密输出。

        理论可行,开始实践。

1 代码详解

1.1 代码总览

#include "openfhe.h"
#include <iostream>
#include <vector>
#include <stdexcept>

using namespace lbcrypto;

extern "C" {
    void perform_homomorphic_operations() {
        try {
            // 第一步:设置加密上下文
            // 创建加密上下文参数对象
            CCParams<CryptoContextBFVRNS> parameters;
            // 设置明文模数为65537
            parameters.SetPlaintextModulus(65537);
            // 设置乘法深度为2
            parameters.SetMultiplicativeDepth(2);

            // 生成加密上下文
            CryptoContext<DCRTPoly> cryptoContext = GenCryptoContext(parameters);
            // 启用公钥加密功能
            cryptoContext->Enable(PKE);
            // 启用密钥切换功能
            cryptoContext->Enable(KEYSWITCH);
            // 启用分层同态加密功能
            cryptoContext->Enable(LEVELEDSHE);

            // 第二步:生成密钥对
            // 生成密钥对对象
            KeyPair<DCRTPoly> keyPair;
            // 生成密钥对
            keyPair = cryptoContext->KeyGen();
            // 生成同态乘法所需的密钥
            cryptoContext->EvalMultKeyGen(keyPair.secretKey);
            // 生成同态旋转所需的密钥,旋转位置为1, 2, -1, -2
            cryptoContext->EvalRotateKeyGen(keyPair.secretKey, {1, 2, -1, -2});

            // 第三步:获取用户输入
            int x;
            std::cout << "请输入要输入的值的数量:";
            std::cin >> x;

            // 检查输入数量是否为正整数
            if (x <= 0) {
                throw std::invalid_argument("输入的数量必须是正整数");
            }

            // 创建一个向量来存储用户输入的值
            std::vector<int64_t> userInput(x);
            std::cout << "请输入 " << x << " 个值:";
            for (int i = 0; i < x; ++i) {
                std::cin >> userInput[i];
            }

            // 第四步:加密
            // 将用户输入的值转换为明文
            Plaintext plaintext = cryptoContext->MakePackedPlaintext(userInput);
            // 加密明文,生成密文
            auto ciphertext = cryptoContext->Encrypt(keyPair.publicKey, plaintext);

            // 第五步:同态运算
            // 创建一个包含顺序值 1, 2, ..., x 的向量
            std::vector<int64_t> seqValues(x);
            for (int i = 0; i < x; ++i) {
                seqValues[i] = i + 1;
            }
            // 将顺序值向量转换为明文
            Plaintext seqPlaintext = cryptoContext->MakePackedPlaintext(seqValues);
            // 加密顺序值明文,生成密文
            auto seqCiphertext = cryptoContext->Encrypt(keyPair.publicKey, seqPlaintext);

            // 同态加法
            auto ciphertextAdd = ciphertext;
            for (int i = 1; i < x; ++i) {
                ciphertextAdd = cryptoContext->EvalAdd(ciphertextAdd, seqCiphertext);
            }

            // 同态乘法
            auto ciphertextMult = ciphertext;
            for (int i = 1; i < x; ++i) {
                ciphertextMult = cryptoContext->EvalMult(ciphertextMult, seqCiphertext);
            }

            // 第六步:解密
            // 解密同态加法结果
            Plaintext plaintextAddResult, plaintextMultResult;
            cryptoContext->Decrypt(keyPair.secretKey, ciphertextAdd, &plaintextAddResult);
            // 解密同态乘法结果
            cryptoContext->Decrypt(keyPair.secretKey, ciphertextMult, &plaintextMultResult);

            // 输出解密结果
            std::cout << "同态加法结果:";
            for (int i = 0; i < x; ++i) {
                std::cout << plaintextAddResult->GetPackedValue()[i] << " ";
            }
            std::cout << std::endl;

            std::cout << "同态乘法结果:";
            for (int i = 0; i < x; ++i) {
                std::cout << plaintextMultResult->GetPackedValue()[i] << " ";
            }
            std::cout << std::endl;

        } catch (const std::exception &e) {
            // 捕获并打印异常信息
            std::cerr << "发生错误:" << e.what() << std::endl;
        }
    }
}

// 添加 main 函数作为程序入口点
int main() {
    perform_homomorphic_operations();
    return 0;
}

        这里直接附上有详细注释的代码片,有一定基础的人相信可以看懂,下面我来详细解释一下这段代码。

1.2 分步解析

1.2.1 设置加密参数

            CCParams<CryptoContextBFVRNS> parameters;
            parameters.SetPlaintextModulus(65537);
            parameters.SetMultiplicativeDepth(2);

            CryptoContext<DCRTPoly> cryptoContext = GenCryptoContext(parameters);
            cryptoContext->Enable(PKE);
            cryptoContext->Enable(KEYSWITCH);
            cryptoContext->Enable(LEVELEDSHE);
  • CCParams:创建一个CCParams对象,用于存储加密的参数。
  • SetPlaintextModulus:设置明文模数为65537,这是明文消息转换为加密形式时使用的模数。
  • SetMultiplicativeDepth:设置同态乘法的深度为2,这决定了可以进行的同态乘法操作的次数。
  • GenCryptoContext:生成加密参数,它包含了加密、解密和同态运算所需的所有信息。
  • Enable:启用不同的功能模块,包括公钥加密(PKE)、密钥切换(KEYSWITCH)和分层同态加密(LEVELEDSHE)。

1.2.2 生成密钥对

KeyPair<DCRTPoly> keyPair;
keyPair = cryptoContext->KeyGen();
cryptoContext->EvalMultKeyGen(keyPair.secretKey);
cryptoContext->EvalRotateKeyGen(keyPair.secretKey, {1, 2, -1, -2});
  • KeyPair:创建一个KeyPair对象,用于存储公钥和私钥。
  • KeyGen:生成公钥和私钥对。
  • EvalMultKeyGen:生成用于同态乘法的评估密钥。
  • EvalRotateKeyGen:生成用于同态旋转的评估密钥,旋转位置包括1、2、-1和-2。

 1.2.3 获取用户输入

int x;
std::cout << "请输入要输入的值的数量:";
std::cin >> x;

if (x <= 0) {
    throw std::invalid_argument("输入的数量必须是正整数");
}

std::vector<int64_t> userInput(x);
std::cout << "请输入 " << x << " 个值:";
for (int i = 0; i < x; ++i) {
    std::cin >> userInput[i];
}
  • 用户输入的数量:提示用户输入要处理的值的数量,并存储在变量x中。
  • 输入验证:检查输入的数量是否为正整数,如果不是,抛出异常。
  • 输入值存储:创建一个向量userInput来存储用户输入的值,并提示用户输入这些值。

 1.2.4 同态运算

std::vector<int64_t> seqValues(x);
for (int i = 0; i < x; ++i) {
    seqValues[i] = i + 1;
}
Plaintext seqPlaintext = cryptoContext->MakePackedPlaintext(seqValues);
auto seqCiphertext = cryptoContext->Encrypt(keyPair.publicKey, seqPlaintext);

// 同态加法
auto ciphertextAdd = ciphertext;
for (int i = 1; i < x; ++i) {
    ciphertextAdd = cryptoContext->EvalAdd(ciphertextAdd, seqCiphertext);
}

// 同态乘法
auto ciphertextMult = ciphertext;
for (int i = 1; i < x; ++i) {
    ciphertextMult = cryptoContext->EvalMult(ciphertextMult, seqCiphertext);
}
  • 创建顺序值向量:创建一个包含顺序值(1, 2, ..., x)的向量。
  • 加密顺序值:将顺序值向量转换为明文并加密,生成密文。
  • 同态加法:进行同态加法操作,将用户输入的密文和顺序值密文相加。
  • 同态乘法:进行同态乘法操作,将用户输入

 1.2.5 输出解密后的结果

            std::cout << "同态加法结果:";
            for (int i = 0; i < x; ++i) {
                std::cout << plaintextAddResult->GetPackedValue()[i] << " ";
            }
            std::cout << std::endl;

            std::cout << "同态乘法结果:";
            for (int i = 0; i < x; ++i) {
                std::cout << plaintextMultResult->GetPackedValue()[i] << " ";
            }
            std::cout << std::endl;

        } catch (const std::exception &e) {
            // 捕获并打印异常信息
            std::cerr << "发生错误:" << e.what() << std::endl;

这一步没什么好过多解释的,就是print一下结果。

2 如何使用

2.1 写入cpp文件

        我的OpenFHE存放在根目录下openfhe-development文件夹下,下面就按照我自己的环境,讲解一下如何导入并使用上面的代码。

        首先,进入cpp文件的保存位置:

cd /openfhe-development/src/pke/examples/

        这一步如果报错的话就一步一步cd一下,方法是固定的,cpp文件存在openfhe安装位置下的src/pke/examples文件夹下。

        进入这个文件夹后,用vi编辑一个新的文档,把上面的代码写进去:

vi jiaohuyunsuan.cpp

        vi后面是我自己编的名字,注意后面要跟.cpp的后缀,文件名要记住,调用的时候会用到。

         进去之后按“i”,然后把上面的代码粘贴到文件里面,按“esc“键,然后:wq保存。

2.2 编译

        编译过程需要进入到openfhe安装路径的build文件夹下,然后直接用make编译文件,我以我的环境举例:

cd openfhe-development/build
make

        等编译好以后,就可以进入到/openfhe-development/build/bin/examples/pke/下查看已经编译好的文件。

2.3 运行

        刚才起的名字叫jiaohuyunsuan.cpp,调用的时候不用带后缀,代码如下:

cd openfhe-development
cd build
bin/examples/pke/jiaohuyunsuan

        结果如图:

如果对你有帮助,请点赞收藏,这是我更新的最大动力。

  • 28
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值