Paillier半同态加密算法及C++实现
Paillier 半同态加密系统详解及C++实现
一、Paillier 同态加密算法
1.1 基本概念
- 质数
- 质数,也称素数,是指只能被1和本身整除的自然数,即大于1的自然数中,除了1和它本身以外,没有其它的因数。比如2、3、5、7、11等都是质数,而4、6、8、9等则不是质数。
- \(\mathbb{Z}_n^*\)
- 表示模 \(n\) 意义下,即 \(0\) ~ \(n-1\) 中所有与 \(n\) 互质的元素的集合。
- \(\mathbb{Z}_{n^2}^*\)
- 表示模 \(n^2\) 意义下的可逆元素集合。具体地,对于正整数 \(n\),\(Z_{n^2}^*\) 包含了模 \(n^2\) 意义下与 \(n^2\) 互质的所有元素。也就是说,如果 \(x\) 属于 \(Z_{n^2}^*\),那么 \(x\) 满足以下两个条件:
- \(x\) 和 \(n^2\) 互质,即\(\gcd(x, n^2) = 1\);
- \(x\) 在模 \(n^2\) 意义下有逆元,即存在 \(y\) 使得 \(xy ≡ 1 \pmod {n^2}\) 。
- 表示模 \(n^2\) 意义下的可逆元素集合。具体地,对于正整数 \(n\),\(Z_{n^2}^*\) 包含了模 \(n^2\) 意义下与 \(n^2\) 互质的所有元素。也就是说,如果 \(x\) 属于 \(Z_{n^2}^*\),那么 \(x\) 满足以下两个条件:
- 欧拉函数 \(\varphi(n)\)
- \(n = pq\),其中 \(p\) 和 \(q\) 是两个质数
- 欧拉函数 \(\varphi(n) = (p-1)(q-1)\) 即为 \(\mathbb{Z}_n^*\) 中的元素个数
- 更进一步,\(\mathbb{Z}_{n^2}^*\) 的元素个数为 \(\varphi(n^2) = n\varphi(n)\)
- 卡迈克尔函数(Carmichael's Function)
- \(\lambda(n)=\text{lcm}(p-1, q-1)\),满足 \(a^{\lambda(n)} \equiv 1 \pmod n\),其中 \(a\) 与 \(n\) 互质。
- 根据卡迈克尔定理(Carmichael's Theorem),对于任意元素 \(\omega \in \mathbb{Z}_{n^2}^*\)
- \(\omega^{\lambda} = 1 \mod n\)
- \(\omega^{n\lambda} = 1 \mod {n^2}\)
- n次剩余
- 在数论中,给定一个正整数 \(a\) 和一个奇素数 \(p\),如果存在整数 \(x\) 使得 \(x^2 \equiv a \pmod p\),那么称 \(a\) 是模 \(p\) 的二次剩余(Quadratic Residue,QR),否则称 \(a\) 是模 \(p\) 的二次非剩余(Quadratic Non-Residue,QNR)。
- 类似地,如果存在整数 \(x\) 使得 \(x^n \equiv a \pmod p\),那么称 \(a\) 是模 \(p\) 的 \(n\) 次剩余(nth Power Residue),否则称 \(a\) 是模 \(p\) 的 \(n\) 次非剩余(nth Power Non-Residue)。
- 当 \(n=2\) 时,\(n\) 次剩余就是二次剩余。\(n\) 次剩余和二次剩余一样,具有很多重要的应用,例如在加密算法和密码学中被广泛使用。
- 复合剩余类问题(Composite Residuosity Problem,CRP)
- 在模 \(n\) 意义下,给定两个整数 \(a\) 和 \(b\),判断是否存在整数 \(x\),使得 \(a \equiv x^2 \pmod n\) 且 \(b \equiv x^2 \pmod n\) 同时成立。其中,\(n\) 是一个合数。
1.2 算法思路
Paillier 半同态加密算法的安全性基于复合剩余类问题(Decisional Composite Residusity Assumption,DCRA)的困难性,即在给出 \(y\) 和 \(n\) 的情况下,很难判断模 \(n^2\) 的 \(n\) 次剩余是否存在: \(z \equiv y^n \pmod {n^2}\)。
1.3 加解密过程
密钥生成 KeyGeneration
- 选择两个随机的大质数 \(p\) 和 \(q\)
- 计算出 \(n = p \cdot q\) 和 \(\lambda(n) = \text{lcm}(p-1,q-1)\)
- 选取随机数 \(g\),\(g \in \mathbb{Z}_{n^2}^*\),且满足 \(\mu = (L(g^{\lambda} \mod {n^2}))^{-1}\)存在,\(L\) 函数定义为\(L(x) = \frac{x-1}{n}\)
- 得到公钥为 \((n,g)\),私钥为 \((\lambda, \mu)\)
加密 Encryption
- 对于明文 \(m\),\(m \in \mathbb{Z}_n\),选择随机数 \(r < n\)
- \(c = \text{Enc}(m, n, g, r) = g^m r^n \pmod {n^2}\)
解密 Decryption
- \(m = \text{Dec}(c, \lambda, \mu) = L(c^{\lambda} \mod {n^2}) * \mu \pmod n = \frac{L(c^{\lambda} \mod {n^2})}{L(g^{\lambda} \mod {n^2})} \pmod n\)
二、C++实现
2.1 实验环境
Linux版本
sino@Aliyun:~$ lsb_release -a
LSB Version: core-11.1.0ubuntu4-noarch:security-11.1.0ubuntu4-noarch
Distributor ID: Ubuntu
Description: Ubuntu 22.04 LTS
Release: 22.04
Codename: jammy
编译器版本
sino@Aliyun:~$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/11/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 11.3.0-1ubuntu1~22.04' --with-bugurl=file:///usr/share/doc/gcc-11/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only
......
gcc version 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04)
在算法的具体实现过程中,需要使用到C++的NTL库和GMP库,所以首先要安装这两个库。
- GMP(GNU Multiple Precision Arithmetic Library)是一款用于高精度计算的C/C++库,可以支持任意长度的整数运算、浮点数运算等操作。
- NTL(Number Theory Library)是一款用于高效实现数论算法的C++库,可以支持任意精度整数、多项式、矩阵等数据类型的操作,包括整数分解、离散对数、RSA公钥加密、椭圆曲线密码等常见数论算法。NTL库的作者是Victor Shoup,目前最新版本为11.5.2,开源免费。
和GMP库相比,NTL库更专注于数论算法的实现,提供了一些高效的数论算法和数据结构,例如NTL提供了快速傅里叶变换(FFT)实现多项式乘法、大数NTT、CRT等。同时,NTL库还提供了一些常见的密码学算法的实现,例如RSA、椭圆曲线密码等。由于NTL库的高效性和专注性,NTL库在一些需要高效实现数论算法的应用中得到了广泛的运用,例如密码学、编码理论等领域。与GMP库相比,NTL库在支持高精度整数计算的同时,还提供了更多的数论算法和数据结构,因此可以看做是GMP库的一个补充和扩展。需要注意的是,由于NTL库的特殊性质,NTL库并不支持任意精度浮点数的计算,因此在需要进行浮点数运算时,还需要结合其他库(例如GMP库)来完成。
2.2 安装GMP的依赖m4
m4是一种宏处理器,用于对文本进行宏扩展,常用于自动生成代码、配置文件等。在GMP的构建过程中,需要使用m4来生成一些C源代码,以实现GMP所支持的高精度计算功能。例如,m4会根据指定的GMP配置参数,生成一些用于高精度计算的函数和数据结构的定义。因此,m4是GMP库的一个必要依赖。
使用该命令安装m4:
sudo apt-get install m4
m4相关信息:
sino@Aliyun:~$ dpkg -s m4
Package: m4
Status: install ok installed
Priority: optional
Section: interpreters
Installed-Size: 346
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Architecture: amd64
Multi-Arch: foreign
Version: 1.4.18-5ubuntu2
Depends: libc6 (>= 2.34), libsigsegv2 (>= 2.9)
Suggests: m4-doc
Description: macro processing language
GNU `m4' is an implementation of the traditional UNIX macro
processor. It is mostly SVR4 compatible, although it has some
extensions (for example, handling more than 9 positional parameters to
macros). `m4' also has builtin functions for including files, running
shell commands, doing arithmetic, etc. Autoconf needs GNU `m4' for
generating `configure' scripts, but not for running them.
Homepage: https://www.gnu.org/software/m4/
Original-Maintainer: Santiago Vila <sanvila@debian.org>
2.3 安装GMP库
在GMP官网有.tar.lz
,.tar.gz
,.tar.zst
版本的压缩文件,可以下载到本地再上传到服务器,也可以复制链接后直接在服务器上使用 wget/curl
下载(这边以gmp-6.2.1为例):
# 1. 使用 wget 下载 gmp-6.2.1.tar.xz
wget https://gmplib.org/download/gmp/gmp-6.2.1.tar.xz
# 2. 或者使用 curl 下载 gmp-6.2.1.tar.xz
curl https://gmplib.org/download/gmp/gmp-6.2.1.tar.xz --output gmp-6.2.1.tar.xz
进行解压:
# 1. 对gmp-6.2.1.tar.xz进行解压
xz -d gmp-6.2.1.tar.xz && tar xvf gmp-6.2.1.tar
# 2. 对gmp-6.2.1.tar.gz进行解压
tar -zxvf gmp-6.2.1.tar.gz
# 3. 解压zst文件需要先安装zstd包,然后再对gmp-6.2.1.tar.zst进行解压
sudo apt install zstd
tar -I zstd -xvf gmp-6.2.1.tar.zst
编译安装GMP:
# 进入gmp目录
cd gmp-6.2.1
# 设置启用C++支持
./configure --enable-cxx
# 开始编译安装,默认安装到/usr/local下
make
make check
sudo make install
可以用该文件进行测试,输入大整数,输出求和结果:
#include <gmpxx.h>
#include <iostream>
#include <stdio.h>
using namespace std;
int main()
{
mpz_t a, b, c;
mpz_init(a);
mpz_init(b);
mpz_init(c);
printf("========= Input a and b => Output a + b =========\n");
printf("[-] a = ");
gmp_scanf("%Zd", a);
printf("[-] b = ");
gmp_scanf("%Zd", b);
mpz_add(c, a, b);
gmp_printf("[+] c = %Zd\n",c);
return 0;
}
输出:
# -lgmp表示连接到gmp库,-lm表示连接到math库
sino@Aliyun:~$ g++ testGMP.cpp -o testGMP -lgmp -lm
sino@Aliyun:~$ ./testGMP
========= Input a and b => Output a + b =========
[-] a = 11111111111111111111111111111111111111111
[-] b = 22222222222222222222222222222222222222222
[+] c = 33333333333333333333333333333333333333333
2.4 安装NTL库
从NTL官网下载对应的压缩包,这里我下载了最新的NTL 11.5.1 (2021.06.23)
。
参考官网文档提供的安装方式进行安装(默认安装到/usr/local
目录下):
% gunzip ntl-xxx.tar.gz
% tar xf ntl-xxx.tar
% cd ntl-xxx/src
% ./configure
% make
% make check
% sudo make install
至此,环境搭建完毕,开始实现具体算法。
2.5 Paillier 加密算法实现
#include <iostream>
#include <ctime>
#include <NTL/ZZ.h>
using namespace std;
using namespace NTL;
// L函数
ZZ L_function(const ZZ &x, const ZZ &n) { return (x - 1) / n; }
/* 密钥生成函数
*
* 参数:
* p:大质数
* q:大质数
* n = p * q
* phi = (p - 1) * (q - 1)
* lambda = lcm(p - 1, q - 1) = (p - 1) * (q - 1) / gcd(p - 1, q - 1)
* g = n + 1
* lamdaInverse = lambda^{-1} mod n^2
* k : 大质数的位数
*/
void keyGeneration(ZZ &p, ZZ &q, ZZ &n, ZZ &phi, ZZ &lambda, ZZ &g, ZZ &lambdaInverse, ZZ &r, const long &k)
{
GenPrime(p, k), GenPrime(q, k);
n = p * q;
g = n + 1;
phi = (p - 1) * (q - 1);
lambda = phi / GCD(p - 1, q - 1);
lambdaInverse = InvMod(lambda, n);
r = RandomBnd(n);
cout << "--------------------------------------------------密钥生成阶段---------------------------------------------------" << endl;
cout << "公钥(n, g) : " << endl;
cout << "n = " << n << endl;
cout << "g = " << g << endl;
cout << "---------------------------------------------------------------------------------------------------------------" << endl;
cout << "私钥(lambda, mu) : " << endl;
cout << "lambda = " << lambda << endl;
cout << "mu = " << lambdaInverse << endl;
}
/* 加密函数
*
* 参数:
* m :需要加密的明文消息
* (n, g) :公钥
*
* 返回值:
* 加密后得到的密文
*/
ZZ encrypt(const ZZ &m, const ZZ &n, const ZZ &g, const ZZ &r)
{
// 生成一个随机数 r < n
// r = RandomBnd(n);
ZZ c = (PowerMod(g, m, n * n) * PowerMod(r, n, n * n) ) % (n * n);
cout << "----------------------------------------------------加密阶段-----------------------------------------------------" << endl;
cout << "密文输出 : " << c << endl;
return c;
}
/* 解密函数
*
* 参数:
* c:密文
* (lambda,lamdaInverse): 私钥
*/
ZZ decrypt(const ZZ &c, const ZZ &n, const ZZ &lambda, const ZZ &lambdaInverse)
{
ZZ m = (L_function(PowerMod(c, lambda, n * n), n) * lambdaInverse) % n;
cout << "----------------------------------------------------解密阶段-----------------------------------------------------" << endl;
cout << "解密得到 : " << m << endl;
return m;
}
void validHomomorphic(const ZZ &c1, const ZZ &c2, const ZZ &n, const ZZ &lambda, const ZZ &lambdaInverse)
{
ZZ c_sum = (c1 * c2) % (n * n);
ZZ m_sum = (L_function(PowerMod(c_sum, lambda, n * n), n) * lambdaInverse) % n;
cout << "----------------------------------------------------验证阶段-----------------------------------------------------" << endl;
cout << "密文相加 : " << c_sum << endl;
cout << "解密得到 : " << m_sum << endl;
}
int main()
{
long k = 1024;
ZZ p, q, n, phi, lambda, lambdaInverse, g, r;
ZZ m1, m2, c1, c2, m1_d, m2_d;
keyGeneration(p, q, n, phi, lambda, g, lambdaInverse, r, k);
cout << "请输入需要加密的明文消息1 : ";
cin >> m1;
cout << "请输入需要加密的明文消息2 : ";
cin >> m2;
c1 = encrypt(m1, n, g, r);
c2 = encrypt(m2, n, g, r);
m1_d = decrypt(c1, n, lambda, lambdaInverse);
m2_d = decrypt(c2, n, lambda, lambdaInverse);
validHomomorphic(c1, c2, n, lambda, lambdaInverse);
return 0;
}
结果展示:
sino@Aliyun:~$ ./test
--------------------------------------------------密钥生成阶段---------------------------------------------------
公钥(n, g) :
n = 13977519274790441656039728824664066566751580225830111297481449507170391163961188972534136723953705922100844638663314088972891610665942579823852325755799480769863965201414410484585993404626784900415288322453980460869150960878586993250127047888188489199968849235283514146555044150166829621643948406905458006676250092961705146148549754780019037177684216540808913196999897637031209503007317844677968929261553270079629721158016943795069823598060252392013545759641913715429908910377626375767622186427516707813998025923748305002149425708073508950815121744994995884683365094798506723782361561071061851331561267151772822627137
g = 13977519274790441656039728824664066566751580225830111297481449507170391163961188972534136723953705922100844638663314088972891610665942579823852325755799480769863965201414410484585993404626784900415288322453980460869150960878586993250127047888188489199968849235283514146555044150166829621643948406905458006676250092961705146148549754780019037177684216540808913196999897637031209503007317844677968929261553270079629721158016943795069823598060252392013545759641913715429908910377626375767622186427516707813998025923748305002149425708073508950815121744994995884683365094798506723782361561071061851331561267151772822627138
---------------------------------------------------------------------------------------------------------------
私钥(lambda, mu) :
lambda = 188885395605276238595131470603568467118264597646352855371370939286086367080556607736947793566941971920281684306261001202336373117107332159781788185889182172565729259478573114656567478440902498654260653006134871092826364336197121530407122268759303908107687151828155596575068164191443643535729032525749432522648828932495789096849140110883355763414692102465869851370273949020747548836135109482745320317984439098473244278779014247699188700796223237422103066948848969720616789152779175123480696138872103888658010428985090114882887120409154424060441852477740489839943146761417505693223440329637274653511943402979227632674
mu = 12588803298112690399414451894599405032468118845247454993011202828694333725052690392388595269553707399158090425889288880208672730787691637670624058983695138956226613385232269722862937004592453326894705633206848669288094113469773944586759602866087821247578442984761182737585990195245138288230695595420981275556643452148705687135042704194755221028793638190583278147450863577524984374726401903550665018308296642783171442707514976439155746638522533178470331231500414372801036869018700536915674927683400535017630788774528311986629726609675518861119346480164418144515479940433672991584289916571335865094108481358154810831657
请输入需要加密的明文消息1 : 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
请输入需要加密的明文消息2 : 222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
----------------------------------------------------加密阶段-----------------------------------------------------
密文输出 : 175937575562556471975946427922583543005293798654572255521490186276908603199820743764479791725169860241333342406515089937015295133921153494292358012826313725899475799995530305107366978174304274493131445368989010913314363412582008965650026574421950201411596184585729172826287080152305652676463681954143149973151401258097243561875814270031473736031698842592566452128010519647063674668029048011525965244663763327041555781886646496631381130513526408821491303493897514482308129356019926302622472852996208625965251912809910831780760942746096897007307701372142233466133267683582321094490762802551351496378800848931254518223326345582515300882288268256001636980703578894638013678399616914210430197813759145675139061458946505697458083425005559040074686778108155866734648891128672226148697858620952011441564194576073239932493580455544691287400048572546219652237499132370274820485547759585231881300036827842339011719488530439904150182061180548606468727607820763194781401479001964391057873902345721622034723046847305937189659104730711067714840011634301577317171586306148837721549709218224835398563004585208208012279439056398683966091031679801554242623563252502628256693972727048476844666737578796996562962917024587002258524545268772477635632459080
----------------------------------------------------加密阶段-----------------------------------------------------
密文输出 : 140701456148456803415628385485741729944625650475886694344592654398833615492855634274068742714414234254602195259858648617776715663965434706048490592884457023494603965059551160318678499207747448977376915241445370806925211072103194195451483916184840152888757825529516679653635630601884595994037107511324625342888365758423430946331358874059597042880034947333666762832620594715149701806839884057981264885016344782254777908265815406538533267612836451805221553813287360731242315743633372602760528477425856851803928136545300800081018397557342995766452120268669292765290716903651440456549677473602295371401833338544673021588675723323647976557962206019885279110463286006289784270033601111700126115815881037595642412504539310421919892531832005323928205174567097762658355803439131213231866892532756368394331798859309576979338514018734205617063461301830632719615930518112658664933629098651981334193625783061667519493130701614169650708235072375455897720213740248510760764115436845888280247787944955568137080185970935146403502756480359885197075959478875727780800916500307004224118259767280256611848713674447726571897281260637241611097559907923596513426401231805512826100712371291615493251635284422713346502880382531290299514968295908421042878497427
----------------------------------------------------解密阶段-----------------------------------------------------
解密得到 : 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
----------------------------------------------------解密阶段-----------------------------------------------------
解密得到 : 222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222
----------------------------------------------------验证阶段-----------------------------------------------------
密文相加 : 32469427208183854745369451361067724812165628334758042163701355588333765987562109057147990301352780225370314566323817157488229017550773362913472766192226209341944530624307055225565813988630800270412613820445427722833751308955834532070473740605864840109906274020981392916834500653459902092782279576087441245134925159768498634787847310186590222182608905659882775456630189121844428234395478528038135833742101475400921071090820162574424482478317003835013554277213672871011526886797143810085964625497092311689407276334163248323792885165634737028728133405852240881379231346856749122340293183206093849536614680156854001392366935071532652065400502715248858335314430228328577165473881573123593864610972055342166991707499890425293488973954033121738183526367571120596533597092153578639535859274901519091051375300429980805527849687534258467388337736358289164262213470737152183265833227609755917238679978588621034382746337858011311322672305611038775837088226786497457022618168507930486068933475292607945227889828044873534423767084842345506959378267004916601006608511900297157809581163839193573522201736067655377955917695455396702908811012864314342876039823026144126268454224810099316331670354842143517171029136878634318211228168905763719003406581
解密得到 : 333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333