1mod utils;
2use num_bigint::{BigInt, RandBigInt, ToBigInt};
3use num_traits::{One, Zero};
4
5use utils::{generate_prime, l, lcm, mod_inverse, mod_pow};
6
7#[derive(Debug, Clone)]
8pub struct PaillierPublicKey {
9 n: BigInt,
10 g: BigInt,
11}
12
13#[derive(Debug, Clone)]
14pub struct PaillierPrivateKey {
15 lambda: BigInt,
16 mu: BigInt,
17 public_key: PaillierPublicKey,
18}
19
20pub fn generate_keypair(bit_length: usize) -> (PaillierPublicKey, PaillierPrivateKey) {
21 let p = generate_prime(bit_length / 2);
22 let q = generate_prime(bit_length / 2);
23
24 let n = &p * &q;
25 let n_squared = &n * &n;
26
27 let lambda = lcm(&(p - 1), &(q - 1));
28 let g: BigInt = &n + 1;
29
30 let mu = mod_inverse(&l(&g.modpow(&lambda, &n_squared), &n), &n);
31
32 let public_key = PaillierPublicKey {
33 n: n.clone(),
34 g: g.clone(),
35 };
36 let private_key = PaillierPrivateKey {
37 lambda,
38 mu,
39 public_key: public_key.clone(),
40 };
41
42 dbg!(&private_key);
43
44 (public_key, private_key)
45}
46
47pub fn encrypt(public_key: &PaillierPublicKey, m: &BigInt) -> BigInt {
48 let mut rng = rand::thread_rng();
49 let r: BigInt = rng.gen_bigint_range(&BigInt::one(), &public_key.n);
50 let n_squared = &public_key.n * &public_key.n;
51
52 (public_key.g.modpow(m, &n_squared) * r.modpow(&public_key.n, &n_squared)) % &n_squared
53}
54
55pub fn decrypt(private_key: &PaillierPrivateKey, c: &BigInt) -> BigInt {
56 let n_squared = &private_key.public_key.n * &private_key.public_key.n;
57 (l(
58 &c.modpow(&private_key.lambda, &n_squared),
59 &private_key.public_key.n,
60 ) * &private_key.mu)
61 % &private_key.public_key.n
62}
63
64pub fn add_encrypted(public_key: &PaillierPublicKey, c1: &BigInt, c2: &BigInt) -> BigInt {
66 let n_squared = &public_key.n * &public_key.n;
67 (c1 * c2) % &n_squared
68}
69
70pub fn additive_inverse(public_key: &PaillierPublicKey, c: &BigInt) -> BigInt {
71 let n_squared = &public_key.n * &public_key.n;
72 mod_pow(c, &(&public_key.n - BigInt::one()), &n_squared)
73}
74
75pub fn subtract_encrypted(public_key: &PaillierPublicKey, c1: &BigInt, c2: &BigInt) -> BigInt {
77 let inverse_c2 = additive_inverse(public_key, c2);
78 add_encrypted(public_key, c1, &inverse_c2)
79}