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\) 满足以下两个条件:
      1. \(x\)\(n^2\) 互质,即\(\gcd(x, n^2) = 1\)
      2. \(x\) 在模 \(n^2\) 意义下有逆元,即存在 \(y\) 使得 \(xy ≡ 1 \pmod {n^2}\)
  • 欧拉函数 \(\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
posted @ 2023-04-14 22:08  S!no  阅读(1509)  评论(1编辑  收藏  举报