Python实现Paillier同态加密算法

Python实现Paillier同态加密算法的博客

引言

Paillier加密算法 是由Pascal Paillier在1999年提出的一种基于计算复杂性的概率性加密算法。它是一种同态加密算法,具有加法同态性,这意味着两个密文相乘的结果解密后等于两个明文相加的结果。Paillier加密算法在隐私保护、数据安全和云计算中应用广泛。本文将详细介绍Paillier加密算法的原理,并使用Python以面向对象的方式实现其加密和解密操作,最后结合一个场景演示其应用。


Paillier加密算法的工作原理

Paillier加密系统依赖于大整数的难题,其安全性基于分解大整数的困难性。算法主要由三个部分组成:密钥生成、加密和解密。

  1. 密钥生成

    • 选择两个大素数 p p p q q q,计算 n = p × q n = p \times q n=p×q λ = lcm ( p − 1 , q − 1 ) \lambda = \text{lcm}(p-1, q-1) λ=lcm(p1,q1),其中 lcm \text{lcm} lcm 是最小公倍数。
    • 选择一个随机整数 g g g,满足 g ∈ Z n 2 ∗ g \in \mathbb{Z}^*_{n^2} gZn2
    • 计算 μ = ( 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 ( u ) = u − 1 n \text{L}(u) = \frac{u - 1}{n} L(u)=nu1
    • 公钥为 ( n , g ) (n, g) (n,g),私钥为 ( λ , μ ) (\lambda, \mu) (λ,μ)
  2. 加密过程

    • 选择要加密的明文消息 m m m,满足 m ∈ Z n m \in \mathbb{Z}_n mZn
    • 随机选择一个整数 r r r,满足 r ∈ Z n ∗ r \in \mathbb{Z}^*_n rZn
    • 计算密文 c = g m × r n m o d    n 2 c = g^m \times r^n \mod n^2 c=gm×rnmodn2
  3. 解密过程

    • 使用私钥 ( λ , μ ) (\lambda, \mu) (λ,μ)解密密文 c c c,计算:
      m = L ( c λ m o d    n 2 ) × μ m o d    n m = \text{L}(c^\lambda \mod n^2) \times \mu \mod n m=L(cλmodn2)×μmodn

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 = E ( m 1 + m 2 ) c_1 \times c_2 \mod n^2 = E(m_1 + m_2) c1×c2modn2=E(m1+m2)

Python 面向对象实现 Paillier 加密算法

接下来,我们将使用 Python 实现一个 Paillier 类,包括密钥生成、加密和解密的方法。

import random
import math

class Paillier:
    def __init__(self, bit_length=512):
        """
        初始化 Paillier 实例,指定密钥长度。
        """
        self.bit_length = bit_length
        self.public_key = None
        self.private_key = None

    def gcd(self, a, b):
        """计算最大公约数"""
        while b != 0:
            a, b = b, a % b
        return a

    def lcm(self, a, b):
        """计算最小公倍数"""
        return abs(a * b) // self.gcd(a, b)

    def modinv(self, a, m):
        """计算模 m 的乘法逆元"""
        m0, x0, x1 = m, 0, 1
        while a > 1:
            q = a // m
            m, a = a % m, m
            x0, x1 = x1 - q * x0, x0
        if x1 < 0:
            x1 += m0
        return x1

    def generate_keys(self):
        """
        生成公钥和私钥。
        """
        # 生成两个大素数 p 和 q
        p = self.generate_prime_number(self.bit_length)
        q = self.generate_prime_number(self.bit_length)
        
        # 计算 n 和 λ
        n = p * q
        lambda_ = self.lcm(p-1, q-1)

        # 选择 g 和计算 μ
        g = n + 1
        mu = self.modinv(self.L(pow(g, lambda_, n**2), n), n)

        # 公钥和私钥
        self.public_key = (n, g)
        self.private_key = (lambda_, mu)
        return self.public_key, self.private_key

    def generate_prime_number(self, bit_length):
        """
        生成指定比特长度的素数。
        """
        while True:
            num = random.getrandbits(bit_length)
            if self.is_prime(num):
                return num

    def is_prime(self, n, k=5):
        """
        使用 Miller-Rabin 算法判断一个数是否为素数。
        """
        if n <= 1:
            return False
        if n <= 3:
            return True
        if n % 2 == 0:
            return False

        r, s = 0, n - 1
        while s % 2 == 0:
            r += 1
            s //= 2
        for _ in range(k):
            a = random.randint(2, n - 1)
            x = pow(a, s, n)
            if x == 1 or x == n - 1:
                continue
            for _ in range(r - 1):
                x = pow(x, 2, n)
                if x == n - 1:
                    break
            else:
                return False
        return True

    def L(self, u, n):
        """计算函数 L(u) = (u - 1) / n"""
        return (u - 1) // n

    def encrypt(self, plaintext):
        """
        使用公钥加密消息。
        :param plaintext: 明文消息 (整数形式)
        :return: 密文
        """
        n, g = self.public_key
        if not (0 <= plaintext < n):
            raise ValueError(f"明文必须在范围 0 到 {n-1} 之间。")

        # 随机选择 r ∈ Z*_n
        r = random.randint(1, n - 1)
        while self.gcd(r, n) != 1:
            r = random.randint(1, n - 1)

        # 计算密文 c = g^m * r^n mod n^2
        c = (pow(g, plaintext, n**2) * pow(r, n, n**2)) % (n**2)
        return c

    def decrypt(self, ciphertext):
        """
        使用私钥解密密文。
        :param ciphertext: 密文
        :return: 明文
        """
        n, g = self.public_key
        lambda_, mu = self.private_key

        # 计算 L(c^λ mod n^2) * μ mod n
        u = pow(ciphertext, lambda_, n**2)
        plaintext = (self.L(u, n) * mu) % n
        return plaintext
代码解析
  1. 类初始化 __init__ 方法:接收一个密钥长度参数,初始化 Paillier 加密系统。

  2. 密钥生成 generate_keys 方法:随机生成两个大素数 p p p q q q,计算 n , λ , g , μ n, \lambda, g, \mu n,λ,g,μ,返回公钥 ( n , g ) (n, g) (n,g)和私钥 ( λ , μ ) (\lambda, \mu) (λ,μ)

  3. 加密 encrypt 方法:使用公钥和随机数 r r r对明文进行加密,生成密文。

  4. 解密 decrypt 方法:使用私钥对密文进行解密,恢复原始明文。

示例场景:银行对账户余额的隐私保护

假设一家银行想要对用户的账户余额进行加密,以保护其隐私。银行使用Paillier加密算法将每个用户的余额加密存储,并且在不解密数据的情况下,可以对所有用户的余额进行同态加法操作,以计算总余额。

# 示例:银行对账户余额的隐私保护

# 1. 银行生成公钥和私钥
paillier = Paillier()
public_key, private_key = paillier.generate_keys()
print(f"银行的公钥: {public_key}")
print(f"银行的私钥: {private_key}")

# 2. 用户 A 和 B 分别加密他们的账户余额
user_a_balance = 1000
user_b_balance = 1500

encrypted_balance_a = paillier.encrypt(user_a_balance)
encrypted_balance_b = paillier.encrypt(user_b_balance)
print(f"用户 A 的加密余额: {encrypted_balance_a}")
print(f"用户 B 的加密余额: {

encrypted_balance_b}")

# 3. 银行计算总余额(同态加密的优势)
total_encrypted_balance = (encrypted_balance_a * encrypted_balance_b) % (public_key[0]**2)
print(f"加密的总余额: {total_encrypted_balance}")

# 4. 银行解密总余额
total_balance = paillier.decrypt(total_encrypted_balance)
print(f"解密的总余额: {total_balance}")

# 确认结果一致
assert total_balance == user_a_balance + user_b_balance, "总余额计算错误!"
总结

在本文中,我们详细介绍了Paillier加密算法的原理,分析了其在同态加密方面的优点。我们使用Python以面向对象的方式实现了Paillier加密算法的加密和解密,并通过银行对用户账户余额的隐私保护场景展示了该算法的实际应用。通过学习Paillier加密算法,读者可以深入理解现代密码学中的同态加密概念及其在隐私保护中的实际应用。

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
当然可以!以下是一个使用Python编写的Paillier同态加密算法的简单实现: ```python import random import math def generate_keypair(keysize): p = generate_prime(keysize // 2) q = generate_prime(keysize // 2) n = p * q g = n + 1 l = (p - 1) * (q - 1) mu = multiplicative_inverse(l, n) public_key = (n, g) private_key = (l, mu) return public_key, private_key def generate_prime(keysize): while True: num = random.randrange(2**(keysize-1), 2**keysize) if is_prime(num): return num def is_prime(num): if num < 2: return False for i in range(2, int(math.sqrt(num)) + 1): if num % i == 0: return False return True def multiplicative_inverse(a, n): t = 0 newt = 1 r = n newr = a while newr != 0: quotient = r // newr t, newt = newt, t - quotient * newt r, newr = newr, r - quotient * newr if r > 1: raise ValueError("a is not invertible") if t < 0: t = t + n return t def encrypt(public_key, plaintext): n, g = public_key while True: r = random.randint(1, n) if math.gcd(r, n) == 1: break c = (pow(g, plaintext, n**2) * pow(r, n, n**2)) % (n**2) return c def decrypt(private_key, ciphertext): l, mu = private_key n = l * mu - 1 c = pow(ciphertext, l, n**2) plaintext = (L(c, n) * mu) % n return plaintext def L(x, n): return (x - 1) // n # 示例用法 plaintext1 = 42 plaintext2 = 17 # 生成密钥对 public_key, private_key = generate_keypair(1024) # 加密 ciphertext1 = encrypt(public_key, plaintext1) ciphertext2 = encrypt(public_key, plaintext2) # 同态加法(加密结果相乘) ciphertext_sum = (ciphertext1 * ciphertext2) % (public_key[0]**2) # 解密 decrypted_sum = decrypt(private_key, ciphertext_sum) print("加密前的数据:", plaintext1, plaintext2) print("加密后的数据:", ciphertext1, ciphertext2) print("解密后的结果:", decrypted_sum) ``` 这只是一个简单的实现,如果需要更完整和安全的Paillier同态加密算法,建议使用现有的加密库或深入了解该算法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闲人编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值