文章目录
- Paillier密码算法
- 一些会用到的数学知识
- Carmichael函数
- Carmichael定理
- 关键结论
- 结论一
- 结论二
- 算法描述
- 密钥生成
- 加密
- 解密
- 参数的选择
- 正确性证明
- 困难问题
- n n n次剩余
- 复合剩余类的困难问题
- 算法的同态性
- 加法同态性
- 数乘同态性
- 扩展到实数域
- 方法1:定点数表示法
- 方法2:分数表示法
- Python的运行实例
- 参考文献
Paillier密码算法
Paillier密码算法由法国学者Pascal Paillier在1999年发表的论文《Public-Key Cryptosystems Based on Composite Degree Residuosity Classes》中首次提出。该算法利用了数论中的复合剩余类的数学性质。该算法因其同态加密特性而广受关注,同态加密允许对加密数据直接进行某些运算,而无需解密数据。
一些会用到的数学知识
Carmichael函数
- 定义:对满足 g c d ( a , n ) = 1 gcd(a,n)=1 gcd(a,n)=1 的所有 a a a,使得 a m ≡ 1 ( m o d n ) a^m \equiv 1 \pmod{n} am≡1(modn)同时成立的最小正整数 m m m,称为 n n n的卡米歇尔(Carmichael)函数,记为 λ ( n ) \lambda(n) λ(n)。
Carmichael定理
λ ( p α ) = { φ ( p α ) , i f ( p r = 2 , 3 r , 4 , 5 r , 7 r , 1 1 r , . . . ) 1 2 φ ( p α ) , i f ( p r = 8 , 16 , 32 , 64 , . . . ) λ ( p 1 α 1 . . . p k α k ) = l c m ( λ ( p 1 α 1 ) , . . . , λ ( p k α k ) ) i f ( a ∣ b ) , t h e n ( λ ( a ) ∣ λ ( b ) ) λ ( l c m ( a , b ) ) = l c m ( λ ( a ) , λ ( b ) ) \begin{aligned} &\lambda(p^\alpha)=\begin{cases}\varphi(p^\alpha),if(p^r=2,3^r,4,5^r,7^r,11^r,...)\\\frac{1}{2}\varphi(p^\alpha),if(p^r=8,16,32,64,...)\end{cases} \\ &\lambda(p_1^{\alpha_1}...p_k^{\alpha_k})=lcm\Big(\lambda(p_1^{\alpha_1}),...,\lambda(p_k^{\alpha_k})\Big) \\ &if(a|b),then\big(\lambda(a)|\lambda(b)\big) \\ &\lambda\big(lcm(a,b)\big)=lcm\big(\lambda(a),\lambda(b)\big) \end{aligned} λ(pα)={φ(pα),if(pr=2,3r,4,5r,7r,11r,...)21φ(pα),if(pr=8,16,32,64,...)λ(p1α1...pkαk)=lcm(λ(p1α1),...,λ(pkαk))if(a∣b),then(λ(a)∣λ(b))λ(lcm(a,b))=lcm(λ(a),λ(b))
关键结论
结论一
对于
n
=
p
q
,
λ
=
λ
(
n
)
=
l
c
m
(
p
−
1
,
q
−
1
)
n=pq,\lambda = \lambda(n)=lcm(p-1,q-1)
n=pq,λ=λ(n)=lcm(p−1,q−1)。对于
∀
r
∈
Z
n
2
∗
\forall r \in \mathbb{Z}_{n^2}^*
∀r∈Zn2∗,有以下两个等式成立:
r
λ
≡
1
(
m
o
d
n
)
r ^ \lambda \equiv 1 \pmod{n}
rλ≡1(modn)
r
λ
n
≡
1
(
m
o
d
n
2
)
r ^ {\lambda n} \equiv 1 \pmod{n^2}
rλn≡1(modn2)
证明:
第一个等式:
λ
=
λ
(
n
)
=
l
c
m
(
p
−
1
,
q
−
1
)
p
−
1
∣
λ
,
q
−
1
∣
λ
λ
=
k
1
(
p
−
1
)
=
k
2
(
q
−
1
)
\begin{aligned} &\lambda=\lambda(n)=lcm(p-1,q-1) \\ &p-1|\lambda,q-1|\lambda \\ &\lambda=k_1(p-1)=k_2(q-1) \end{aligned}
λ=λ(n)=lcm(p−1,q−1)p−1∣λ,q−1∣λλ=k1(p−1)=k2(q−1)
根据费马小定理
r
λ
=
r
k
1
(
p
−
1
)
=
(
r
(
p
−
1
)
)
k
1
≡
1
mod
p
,所以
r
λ
−
1
≡
0
mod
p
r
λ
=
r
k
2
(
q
−
1
)
=
(
r
(
q
−
1
)
)
k
2
≡
1
mod
q
,所以
r
λ
−
1
≡
0
mod
q
r^{\lambda}=r^{k_{1}(p-1)}=(r^{(p-1)})^{k_{1}}\equiv1\operatorname{mod}p\text{,所以}r^{\lambda}-1\equiv0\operatorname{mod}p\\r^{\lambda}=r^{k_{2}(q-1)}=(r^{(q-1)})^{k_{2}}\equiv1\operatorname{mod}q\text{,所以}r^{\lambda}-1\equiv0\operatorname{mod}q
rλ=rk1(p−1)=(r(p−1))k1≡1modp,所以rλ−1≡0modprλ=rk2(q−1)=(r(q−1))k2≡1modq,所以rλ−1≡0modq
所以
r
λ
−
1
≡
0
(
m
o
d
p
q
)
r^\lambda-1\equiv0 \pmod{pq}
rλ−1≡0(modpq)
r
λ
≡
1
(
m
o
d
n
)
r ^ \lambda \equiv 1 \pmod{n}
rλ≡1(modn)
第二个等式:
n
=
p
⋅
q
,
n
2
=
p
2
⋅
q
2
n=p\cdot q,n^2=p^2\cdot q^2
n=p⋅q,n2=p2⋅q2,根据Carmichael定理有
λ
(
n
2
)
=
l
c
m
(
λ
(
q
2
)
,
λ
(
p
2
)
)
=
l
c
m
(
φ
(
q
2
)
,
φ
(
p
2
)
)
=
l
c
m
(
q
⋅
φ
(
q
)
,
p
⋅
φ
(
p
)
)
=
l
c
m
(
q
(
q
−
1
)
,
p
(
p
−
1
)
)
=
p
q
(
l
c
m
(
p
−
1
,
q
−
1
)
)
=
n
λ
(
n
)
\begin{aligned} &\lambda(n^2)=lcm\Big(\lambda(q^2),\lambda(p^2)\Big)=lcm\Big(\varphi(q^2),\varphi(p^2)\Big)=lcm\Big(q\cdot\varphi(q),p\cdot\varphi(p)\Big) \\ &=lcm\big(q(q-1),p(p-1)\big)=pq\big(lcm(p-1,q-1)\big)=n\lambda(n) \\ \end{aligned}
λ(n2)=lcm(λ(q2),λ(p2))=lcm(φ(q2),φ(p2))=lcm(q⋅φ(q),p⋅φ(p))=lcm(q(q−1),p(p−1))=pq(lcm(p−1,q−1))=nλ(n)
r
λ
≡
r
λ
(
n
)
≡
1
mod
n
r
λ
(
n
2
)
≡
1
mod
n
2
r
n
λ
(
n
)
≡
1
mod
n
2
r^{\lambda}\equiv r^{\lambda(n)}\equiv1\operatorname{mod}n\\r^{\lambda(n^{2})}\equiv1\operatorname{mod}n^{2}\\r^{n\lambda(n)}\equiv1\operatorname{mod}n^{2}
rλ≡rλ(n)≡1modnrλ(n2)≡1modn2rnλ(n)≡1modn2
证毕。
结论二
二项式泰勒展开如下:
(
1
+
n
)
x
=
∑
k
=
0
x
C
x
k
n
k
=
1
+
n
x
+
x
(
x
−
1
)
2
!
n
2
+
.
.
.
+
x
(
x
−
1
)
⋅
.
.
.
⋅
(
x
−
n
+
1
)
n
!
n
n
+
.
.
.
(1+n)^x=\sum_{k=0}^xC_x^kn^k=1+nx+\frac{x(x-1)}{2!}n^2+...+\frac{x(x-1)\cdot...\cdot(x-n+1)}{n!}n^n+...
(1+n)x=k=0∑xCxknk=1+nx+2!x(x−1)n2+...+n!x(x−1)⋅...⋅(x−n+1)nn+...
在模
n
2
n^2
n2的情况下,有:
(
1
+
n
)
x
mod
n
2
=
1
+
n
x
mod
n
2
(1+n)^x\operatorname{mod}n^2=1+nx\operatorname{mod}n^2
(1+n)xmodn2=1+nxmodn2
算法描述
密钥生成
- 选择两个大素数 p p p 和 q q q,计算 n = p q n = pq n=pq 和 λ = lcm ( p − 1 , q − 1 ) \lambda = \text{lcm}(p-1, q-1) λ=lcm(p−1,q−1)( lcm \text{lcm} lcm是最小公倍数)。
- 选择随机整数 g ∈ Z n 2 ∗ g \in \mathbb{Z}_{n^2}^* g∈Zn2∗( g g g 应该满足 g = n + 1 g = n+1 g=n+1 是最简单且常用的选择)。
- 计算 μ = ( L ( g λ m o d n 2 ) ) − 1 m o d n \mu = (\text{L}(g^\lambda \mod n^2))^{-1} \mod n μ=(L(gλmodn2))−1modn,其中 L ( x ) = x − 1 n \text{L}(x) = \frac{x-1}{n} L(x)=nx−1。
- 公钥是 ( n , g ) (n, g) (n,g),私钥是 ( λ , μ ) (\lambda, \mu) (λ,μ)。
加密
将消息
m
∈
Z
n
m \in \mathbb{Z}_n
m∈Zn 转换成密文
c
c
c :
c
=
g
m
⋅
r
n
m
o
d
n
2
c = g^m \cdot r^n \mod n^2
c=gm⋅rnmodn2
其中
r
∈
{
1
,
⋯
,
n
−
1
}
r \in\{1,\cdots,n-1\}
r∈{1,⋯,n−1} 是一个随机数。
解密
用私钥
λ
\lambda
λ 解密密文
c
c
c 得到明文
m
m
m:
m
=
L
(
c
λ
m
o
d
n
2
)
⋅
μ
m
o
d
n
=
L
(
c
λ
m
o
d
n
2
)
L
(
g
λ
m
o
d
n
2
)
m
o
d
n
m=\textrm{L}(c^{\lambda} \mod n^{2})\cdot \mu \mod n = \frac{\textrm{L}(c^{\lambda}\mod n^{2})}{\textrm{L}(g^{\lambda}\mod n^{2})}\mod n
m=L(cλmodn2)⋅μmodn=L(gλmodn2)L(cλmodn2)modn
参数的选择
对于 p p p 和 q q q 的选择,一般满足以下条件:
- p ≠ q p \neq q p=q
- p p p 和 q q q 长度相同,即满足 gcd ( p q , ( p − 1 ) ( q − 1 ) ) = 1 \gcd\bigl(pq,(p-1)(q-1)\bigr)=1 gcd(pq,(p−1)(q−1))=1。
g g g 一般选取为 n + 1 n+1 n+1 。
正确性证明
仅证 g = n + 1 g = n+1 g=n+1的情况,其他情况可以查找资料。
证明:
c
=
g
m
⋅
r
n
mod
n
2
c=g^m\cdot r^n\operatorname{mod}n^2
c=gm⋅rnmodn2
c
λ
m
o
d
n
2
=
g
λ
m
⋅
r
λ
n
m
o
d
n
2
=
g
λ
m
⋅
1
m
o
d
n
2
=
(
1
+
n
)
m
λ
m
o
d
n
2
=
1
+
n
m
λ
m
o
d
n
2
c^\lambda\bmod n^2=g^{\lambda m}\cdot r^{\lambda n}\bmod n^2=g^{\lambda m}\cdot1\bmod n^2=(1+n)^{m\lambda}\bmod n^2=1+nm\lambda\bmod n^2
cλmodn2=gλm⋅rλnmodn2=gλm⋅1modn2=(1+n)mλmodn2=1+nmλmodn2
g
λ
m
o
d
n
2
=
(
1
+
n
)
λ
m
o
d
n
2
=
1
+
n
λ
m
o
d
n
2
g^\lambda\bmod n^2=(1+n)^\lambda\bmod n^2=1+n\lambda\bmod n^2
gλmodn2=(1+n)λmodn2=1+nλmodn2
L
(
c
λ
m
o
d
n
2
)
=
c
λ
m
o
d
n
2
−
1
n
=
m
λ
m
o
d
n
2
L(c^\lambda\bmod n^2)=\frac{c^\lambda\bmod n^2-1}{n}=m\lambda\bmod n^2
L(cλmodn2)=ncλmodn2−1=mλmodn2
L
(
g
λ
m
o
d
n
2
)
=
g
λ
m
o
d
n
2
−
1
n
=
λ
m
o
d
n
2
L(g^\lambda\bmod n^2)=\frac{g^\lambda\bmod n^2-1}{n}=\lambda\bmod n^2
L(gλmodn2)=ngλmodn2−1=λmodn2
m
=
L
(
c
λ
m
o
d
n
2
)
L
(
g
λ
m
o
d
n
2
)
m
o
d
n
m=\frac{L(c^\lambda\bmod n^2)}{L(g^\lambda\bmod n^2)}\bmod n
m=L(gλmodn2)L(cλmodn2)modn
困难问题
n n n次剩余
- 若存在一个整数 y y y,使得 y n ≡ z ( m o d n 2 ) y^n \equiv z \pmod{n^2} yn≡z(modn2) 成立,则 z z z是 n 2 n^2 n2的一个 n n n次剩余。
复合剩余类的困难问题
- 给出合数 n n n和整数 z z z,很难确定 z z z是否为 n n n残差模 n 2 n^2 n2,即给定 y ∈ Z n 2 ∗ , z ≡ y n ( m o d n 2 ) y \in \mathbb{Z}_{n^2}^*, z \equiv y^n \pmod{n^2} y∈Zn2∗,z≡yn(modn2),判定 z z z是模 n 2 n^2 n2的 n n n次剩余还是非剩余是困难的。
该问题目前被认为在多项式时间内难以解决,这是Paillier加密系统的主要安全假设。
算法的同态性
Paillier加密算法的同态特性表现为:
加法同态性
对两个明文
m
1
m_1
m1 和
m
2
m_2
m2,其对应的密文分别为
c
1
c_1
c1 和
c
2
c_2
c2。有:
c
1
⋅
c
2
m
o
d
n
2
=
(
g
m
1
⋅
r
1
n
)
⋅
(
g
m
2
⋅
r
2
n
)
m
o
d
n
2
=
g
m
1
+
m
2
⋅
(
r
1
r
2
)
n
m
o
d
n
2
c_1 \cdot c_2 \mod n^2 = (g^{m_1} \cdot r_1^n) \cdot (g^{m_2} \cdot r_2^n) \mod n^2 = g^{m_1 + m_2} \cdot (r_1 r_2)^n \mod n^2
c1⋅c2modn2=(gm1⋅r1n)⋅(gm2⋅r2n)modn2=gm1+m2⋅(r1r2)nmodn2
解密
c
1
⋅
c
2
m
o
d
n
2
c_1 \cdot c_2 \mod n^2
c1⋅c2modn2 得到
m
1
+
m
2
m_1 + m_2
m1+m2。
数乘同态性
对于明文
m
m
m 和常数
k
k
k,其对应的密文为
c
c
c。有:
c
k
m
o
d
n
2
=
(
g
m
⋅
r
n
)
k
m
o
d
n
2
=
g
m
k
⋅
r
k
n
m
o
d
n
2
c^k \mod n^2 = (g^m \cdot r^n)^k \mod n^2 = g^{mk} \cdot r^{kn} \mod n^2
ckmodn2=(gm⋅rn)kmodn2=gmk⋅rknmodn2
解密
c
k
m
o
d
n
2
c^k \mod n^2
ckmodn2 得到
m
k
mk
mk。
这些同态特性使得Paillier密码算法在需要保留数据隐私的计算中具有广泛的应用,例如电子投票和隐私保护的数据分析。
扩展到实数域
方法1:定点数表示法
一种直接的方法是将实数转换为定点数(固定小数点数),然后使用Paillier加密整数的方式进行加密和解密。具体步骤如下:
- 选择一个缩放因子 s = 1 0 k s = 10 ^ k s=10k,其中 k k k是需要保留的小数位数;
- 将实数 x x x 转换为整数 X X X : X = ⌊ x × s ⌋ X = \lfloor x \times s \rfloor X=⌊x×s⌋;
- 使用Paillier加密整数 X X X 得到密文 c c c ;
- 解密得到整数 X X X ,然后将其转换回实数 x x x ,即 x = X / s x = X / s x=X/s。
对于负数
−
x
-x
−x 的处理主要将其变为
−
x
+
n
-x + n
−x+n 。
经过这样的处理后,加密的数字的范围将会从
{
0
,
1
,
⋯
,
n
}
\{0,1, \cdots, n\}
{0,1,⋯,n} 缩小为
{
0
,
1
,
⋯
,
⌊
n
/
2
s
⌋
}
\{0,1, \cdots, \lfloor n/2s \rfloor \}
{0,1,⋯,⌊n/2s⌋}
方法2:分数表示法
另一种方法是将实数表示为分数,然后分别对分子和分母进行加密。这种方法更适用于需要高精度的场景。
Python的运行实例
需要先安装 phe
和 gmpy2
库,可以使用 pip install xxx
命令安装。
from phe import paillier
import gmpy2 as gy
# 生成 Paillier 密钥对
public_key, private_key = paillier.generate_paillier_keypair(n_length=128)
print("n: ", public_key.n)
print("g: ", public_key.g)
print("p: ",private_key.p)
print("q: ",private_key.q)
a = 15
b = 20
print("a: ",a)
print("b: ",b)
# 加密 a 和 b
a_enc = public_key.encrypt(a)
print("a_enc: ",a_enc.ciphertext())
b_enc = public_key.encrypt(b)
print("b_enc: ",b_enc.ciphertext())
print("同态加")
print("a + b = ",a+b)
c_enc = a_enc + b_enc
print("c_enc = a_enc + b_enc: ",c_enc.ciphertext())
c_dec = private_key.decrypt(c_enc)
print("c_dec = a + b: ",c_dec)
print("同态数乘")
print("a * b = ",a*b)
c1_enc = a * b_enc
print("c1_enc = a * b_enc: ",c1_enc.ciphertext())
c2_enc = b * a_enc
print("c2_enc = b * a_enc: ",c2_enc.ciphertext())
c1_dec = private_key.decrypt(c1_enc)
c2_dec = private_key.decrypt(c2_enc)
print("c1_dec = a * b: ",c1_dec)
print("c2_dec = b * a: ",c2_dec)