1. 引言
OpenMined团队2020年7月9日博客 What is the Paillier cryptosystem? 是其 Privacy-Preserving Data Science, Explained 系列文章的一部分。
本文介绍了Paillier加密系统:
- Paillier加密系统是一种部分同态加密方案。
- 可将其作为私有集合交集(Private set intersection,PSI)协议的基础。
相关开源代码实现见:
- https://github.com/willclarktech/privacy-implementations/tree/ac7133a/src/cryptosystem/paillier(Node.js Typescript,仅供学习,勿用于生产)
- https://github.com/OpenMined/paillier.js(纯Javascript版本,不依赖于
bigint或worker,性能慢) - https://github.com/data61/python-paillier(Python)
- https://github.com/bnb-chain/tss-lib/tree/master/crypto/paillier(Go,已审计)
- https://github.com/ZenGo-X/zk-paillier(Rust,内含一些Paillier加密的ZKP证明)
- https://github.com/ZenGo-X/rust-paillier(Rust)
2. 何为同态加密?
同态加密是一种允许在加密数据上执行数学或逻辑操作的加密形式。如:
- 假设有两个数字 m 1 m_1 m1 和 m 2 m_2 m2 ,使用某种公钥加密方案加密这些数字,公钥为 pub \text{pub} pub ,私钥为 priv \text{priv} priv 。
- 得到两个密文 c 1 = E pub ( m 1 ) c_1 = E_{\text{pub}}(m_1) c1=Epub(m1) 和 c 2 = E pub ( m 2 ) c_2 = E_{\text{pub}}(m_2) c2=Epub(m2) 。通常,加密的目的是使所有加密的数字对没有私钥的人来说无法区分随机数字。
然而,在同态加密中,一些关系得以保留。如:
- 若有一个支持加法的同态加密方案,则会有一个函数 add \text{add} add ,任何人都可以对 c 1 c_1 c1 和 c 2 c_2 c2 执行,使得结果 add pub ( c 1 , c 2 ) \text{add}_{\text{pub}}(c_1, c_2) addpub(c1,c2) 解密后等于 m 1 m_1 m1 和 m 2 m_2 m2 之和:
D priv ( add pub ( E pub ( m 1 ) , E pub ( m 2 ) ) ) = m 1 + m 2 D_{\text{priv}}(\text{add}_{\text{pub}}(E_{\text{pub}}(m_1), E_{\text{pub}}(m_2))) = m_1 + m_2 Dpriv(addpub(Epub(m1),Epub(m2)))=m1+m2
注意,这里的 add \text{add} add 函数不一定是字面上的加法,而是根据相关同态加密方案定义的任何执行此角色的函数。
- 部分同态加密方案已经存在相当长时间,可以对加密数据执行有限的操作,如仅支持加法或仅支持乘法。
- 全同态加密方案在过去十年左右的时间里被开发出来,支持对加密数据进行任意计算。
3. 何为Paillier 加密系统?
Paillier 加密系统 由Pascal Paillier 在其1999年论文《Public-Key Cryptosystems Based on Composite Degree Residuosity Classes》(发表于EUROCRYPT ’99)中提出。
Paillier 加密系统:
- 是一个部分同态加密方案,
- 是一个公钥加密方案。
其允许执行两种类型的计算:
- 两个密文的加法
- 一个密文与明文数字的乘法
3.1 公钥加密方案
基本的公钥加密方案有三个阶段:
- 1)生成一对公钥和私钥
- 2)加密一个数字
- 3)解密一个数字
3.2 Paillier 加密系统的helper functions 辅助函数
Paillier 加密系统的helper functions 辅助函数有:
- 1) gcd ( x , y ) \text{gcd}(x,y) gcd(x,y) :输出 x x x 和 y y y 的最大公约数。
- 2) lcm ( x , y ) \text{lcm}(x,y) lcm(x,y) :输出 x x x 和 y y y 的最小公倍数。
3.3 Paillier 加密系统的密钥生成
Paillier 加密系统的密钥生成过程如下:
- 1)随机独立选择两个大素数 p p p 和 q q q ,确认 gcd ( p ⋅ q , ( p − 1 ) ( q − 1 ) ) = 1 \text{gcd}(p \cdot q, (p - 1)(q - 1)) = 1 gcd(p⋅q,(p−1)(q−1))=1 ,如果不成立,则重新选择。
- 2)计算 n = p ⋅ q n = p \cdot q n=p⋅q 。
- 3)定义函数 L ( x ) = x − 1 n L(x) = \frac{x - 1}{n} L(x)=nx−1 。
- 4)计算 λ \lambda λ 为 lcm ( p − 1 , q − 1 ) \text{lcm}(p - 1, q - 1) lcm(p−1,q−1) 。
- 5)从 Z n 2 ∗ \mathbb{Z}_{n^2}^* Zn2∗ 中选择一个随机整数 g g g (即 1 到 n 2 n^2 n2 之间的整数)。
- 6)计算模乘逆 μ = ( L ( g λ m o d n 2 ) ) − 1 m o d n \mu = \left(L(g^\lambda \mod n^2)\right)^{-1} \mod n μ=(L(gλmodn2))−1modn ,如果 μ \mu μ 不存在,则从步骤1)重新开始。
- 7)公钥为 ( n , g ) (n, g) (n,g) ,用于加密。
- 8)私钥为 ( λ , μ ) (\lambda,\mu) (λ,μ) ,用于解密。
3.4 Paillier 加密
Paillier 加密可以用于范围为 0 ≤ m < n 0 \leq m < n 0≤m<n 的任何数字 m m m :
- 1)从范围 0 < r < n 0 < r < n 0<r<n 中选择一个随机数 r r r 。
- 2)计算密文 c = g m ⋅ r n m o d n 2 c = g^m \cdot r^n \mod n^2 c=gm⋅rnmodn2 。
3.5 Paillier 解密
Paillier 解密假设密文是通过上述加密过程创建的,因此 c c c 在范围 0 < c < n 2 0 < c < n^2 0<c<n2 内:
- 1)计算明文 m = L ( c λ m o d n 2 ) ⋅ μ m o d n m = L(c^\lambda \mod n^2) \cdot \mu \mod n m=L(cλmodn2)⋅μmodn 。
注意:
- 始终可以根据 λ \lambda λ 和公钥重新计算 μ \mu μ 。
- 设
n
=
p
q
n = pq
n=pq ,其中
p
p
p 和
q
q
q 是大素数:用
φ
(
n
)
\varphi(n)
φ(n) 表示Euler函数,用
λ
(
n
)
\lambda(n)
λ(n) 表示Carmichael函数,二者取自
n
n
n ,即在此有:
φ ( n ) = ( p − 1 ) ( q − 1 ) 和 λ ( n ) = lcm ( p − 1 , q − 1 ) \varphi(n) = (p - 1)(q - 1) \quad \text{和} \quad \lambda(n) = \text{lcm}(p - 1, q - 1) φ(n)=(p−1)(q−1)和λ(n)=lcm(p−1,q−1)
回顾一下, ∣ Z n 2 ∗ ∣ = φ ( n 2 ) = n φ ( n ) |\mathbb{Z}^*_{n^2}| = \varphi(n^2) = n\varphi(n) ∣Zn2∗∣=φ(n2)=nφ(n) ,且对于任意 w ∈ Z n 2 ∗ w \in \mathbb{Z}^*_{n^2} w∈Zn2∗ ,根据Carmichael定理,有以下结论:【为视觉上舒适,采用 λ \lambda λ 来代替 λ ( n ) \lambda(n) λ(n) 】
w λ = 1 ( mod n ) 和 w n λ = 1 ( mod n 2 ) w^\lambda = 1 \ (\text{mod} \ n) \quad \text{和} \quad w^{n\lambda} = 1 \ (\text{mod} \ n^2) wλ=1 (mod n)和wnλ=1 (mod n2)
3.6 Paillier 加密系统示例
Paillier 加密系统示例为:
- 1)密钥生成:
- 1.1)选择 p = 13 p = 13 p=13 和 q = 17 q = 17 q=17 。(它们满足条件。)
- 1.2)计算 n = 221 n = 221 n=221 。
- 1.3)计算 λ = 48 \lambda = 48 λ=48 。
- 1.4)选择 g = 4886 g = 4886 g=4886 。
- 1.5)计算 μ = 159 \mu = 159 μ=159 (即存在)。
- 2)加密:
- 2.1)设置 m 1 = 123 m_1 = 123 m1=123 。
- 2.2)选择 r 1 = 666 r_1 = 666 r1=666 。
- 2.3)计算密文 c 1 = 25889 m o d 22 1 2 c_1 = 25889 \mod 221^2 c1=25889mod2212 。
- 3)解密:
- 3.1)计算解密后的明文 m decrypted = 123 m o d 221 m_{\text{decrypted}} = 123 \mod 221 mdecrypted=123mod221 (与 m 1 m_1 m1 相同)。
不过需注意:
- 以上示例中的这些数字太小,无法提供任何实际的安全性,且所选随机值也并不完全随机。
3.7 Paillier 加密系统的同态性质
Paillier 加密系统的同态性质有:
- 1)两个密文的“加法”:
当两个密文相乘时,结果解密后会得到它们明文的和:
D priv ( E pub ( m 1 ) × E pub ( m 2 ) m o d n 2 ) = ( m 1 + m 2 ) m o d n ⇒ c 1 × c 2 = m 1 + m 2 D_{\text{priv}}\left( E_{\text{pub}}(m_1) \times E_{\text{pub}}(m_2) \mod n^2 \right) = (m_1 + m_2) \mod n \quad \Rightarrow \quad c_1 \times c_2 = m_1 + m_2 Dpriv(Epub(m1)×Epub(m2)modn2)=(m1+m2)modn⇒c1×c2=m1+m2 - 2)一个密文与明文的乘法:
当一个密文与一个明文相乘时,结果解密后会得到它们明文的积:
D priv ( E pub ( m 1 ) m 2 m o d n 2 ) = ( m 1 × m 2 ) m o d n ⇒ c 1 m 2 = m 1 × m 2 D_{\text{priv}}\left( E_{\text{pub}}(m_1)^{m_2} \mod n^2 \right) = (m_1 \times m_2) \mod n \quad \Rightarrow \quad c_1^{m_2} = m_1 \times m_2 Dpriv(Epub(m1)m2modn2)=(m1×m2)modn⇒c1m2=m1×m2
3.8 注意事项
有几个特殊情况需要特别小心处理:
- 1)第一个是与 0 相乘。 因为任何数的 0 次方都是 1,如果按上述方法将一个密文与明文 0 相乘,结果总是 1,任何看到这个“加密”值的人都会知道它解密后是 0。
- 幸运的是,可以为这种情况使用另一种方法:
- 因为任何数与 0 相乘都得到 0,可以跳过计算,直接使用标准的公钥加密方案加密 0。由于加密步骤中引入了随机数,任何没有私钥的人都无法知道明文是什么。
- 幸运的是,可以为这种情况使用另一种方法:
- 2)另一个情况是与 1 相乘。 因为任何数
x
x
x 的 1 次方是
x
x
x ,如果按正常方法将一个密文与明文 1 相乘,输出将与输入相同。
- 这比与 0 相乘的情况不那么严重,因为在后者中加密值可以被推测出来,
- 但仍然是一个问题,因为任何监视私钥持有者与执行乘法操作的人的通信的人都可以推断出数字是与 1 相乘的。
- 解决方案是另一种变通方法:
- 不直接与 1 相乘,而是执行一个等效的操作:加 0!直接加密一个 0,然后执行常规的加法程序来获得一个安全的密文。
3.8.1 Paillier 加密 同态运算特殊情况示例
在上面“3.6 Paillier 加密系统示例”的基础之上,介绍Paillier 加密 同态运算特殊情况示例为:
- 1)同态加法:
- 1.1)设置 m 2 = 37 m_2 = 37 m2=37 。
- 1.2)选择 r 2 = 999 r_2 = 999 r2=999 。
- 1.3)计算密文 c 2 = 30692 m o d 22 1 2 c_2 = 30692 \mod 221^2 c2=30692mod2212 。
- 1.4)计算密文和 c sum = 25889 ⋅ 30692 = 39800 m o d 22 1 2 c_{\text{sum}} = 25889 \cdot 30692 = 39800 \mod 221^2 csum=25889⋅30692=39800mod2212 。
- 1.5)计算明文和 m sum = 160 = 123 + 37 = m 1 + m 2 m o d 221 m_{\text{sum}} = 160 = 123 + 37 = m_1 + m_2 \mod 221 msum=160=123+37=m1+m2mod221 。
- 2)同态乘法:
- 2.1)设置 m 3 = 25 m_3 = 25 m3=25 。
- 2.2)计算密文积 c product = 2588 9 25 = 15723 m o d 22 1 2 c_{\text{product}} = 25889^{25} = 15723 \mod 221^2 cproduct=2588925=15723mod2212 。
- 2.3)计算明文积 m product = 202 = 123 ⋅ 25 = m 1 ⋅ m 3 m o d 221 m_{\text{product}} = 202 = 123 \cdot 25 = m_1 \cdot m_3 \mod 221 mproduct=202=123⋅25=m1⋅m3mod221 。
- 3)与 0 相乘:
- 3.1)设置 m multiply0 = 0 m_{\text{multiply0}} = 0 mmultiply0=0 。
- 3.2)选择 r multiply0 = 444 r_{\text{multiply0}} = 444 rmultiply0=444 。
- 3.3)计算密文 c multiply0 = 46663 m o d 22 1 2 c_{\text{multiply0}} = 46663 \mod 221^2 cmultiply0=46663mod2212 。
- 3.4)计算解密后的明文 m decrypted = 0 = 123 ⋅ 0 = m 1 ⋅ 0 m o d 221 m_{\text{decrypted}} = 0 = 123 \cdot 0 = m_1 \cdot 0 \mod 221 mdecrypted=0=123⋅0=m1⋅0mod221 。
- 4)与 1 相乘:
- 4.1)设置 m encrypt0 = 0 m_{\text{encrypt0}} = 0 mencrypt0=0 。
- 4.2)选择 r encrypt0 = 555 r_{\text{encrypt0}} = 555 rencrypt0=555 。
- 4.3)计算密文 c encrypt0 = 653 m o d 22 1 2 c_{\text{encrypt0}} = 653 \mod 221^2 cencrypt0=653mod2212 。
- 4.4)计算密文 c multiply1 = 25889 ⋅ 653 = 6531 m o d 22 1 2 c_{\text{multiply1}} = 25889 \cdot 653 = 6531 \mod 221^2 cmultiply1=25889⋅653=6531mod2212 。
- 4.5)计算明文 m multiply1 = 123 = 123 ⋅ 1 = m 1 ⋅ 1 m o d 221 m_{\text{multiply1}} = 123 = 123 \cdot 1 = m_1 \cdot 1 \mod 221 mmultiply1=123=123⋅1=m1⋅1mod221 。
4. Paillier 加密系统代码实现
以https://github.com/willclarktech/privacy-implementations/tree/ac7133a/src/cryptosystem/paillier(Node.js Typescript,仅供学习,勿用于生产)中代码为例:
假设已安装了 Git 和 Node.js(包括 npm):
git clone https://github.com/willclarktech/privacy-implementations.git
cd privacy-implementations
npm install
npm run build
然后在一个 JavaScript 文件或 Node.js REPL 中:
const paillier = require("./build/cryptosystem/paillier");
const keys = paillier.generateKeysSync(); // 慢!
const plaintext1 = 1234567890n;
const plaintext2 = 55555555555n;
const ciphertext1 = paillier.encrypt(keys.pub)(plaintext1);
const ciphertext2 = paillier.encrypt(keys.pub)(plaintext2);
const ciphertextSum = paillier.add(keys.pub)(ciphertext1, ciphertext2);
const plaintextSum = paillier.decrypt(keys)(ciphertextSum); // 56790123445n = plaintext1 + plaintext2
const ciphertextProduct = paillier.multiply(keys.pub)(ciphertext1, plaintext2);
const plaintextProduct = paillier.decrypt(keys)(ciphertextProduct); // 68587104999314128950n = plaintext1 * plaintext2
const ciphertextMultiply0 = paillier.multiply(keys.pub)(ciphertext1, 0n); // != 1n
const ciphertextMultiply1 = paillier.multiply(keys.pub)(ciphertext1, 1n); // != ciphertext1
参考资料
[1] OpenMined团队2020年7月9日博客 What is the Paillier cryptosystem?
[2] 2021年课件 Paillier Cryptosystem
[3] Pascal Paillier 1999年论文《Public-Key Cryptosystems Based on Composite Degree Residuosity Classes》,发表于EUROCRYPT ’99。
4万+

被折叠的 条评论
为什么被折叠?



