fast_paillier/
decryption_key.rs1use rand_core::{CryptoRng, RngCore};
2
3use crate::backend::Integer;
4use crate::{utils, Ciphertext, EncryptionKey, Nonce, Plaintext};
5use crate::{Error, Reason};
6
7#[derive(Clone)]
9pub struct DecryptionKey {
10 ek: EncryptionKey,
11 lambda: Integer,
13 mu: Integer,
15
16 p: Integer,
17 q: Integer,
18
19 crt_mod_nn: utils::CrtExp,
20 exp_n: utils::Exponent,
22 exp_lambda: utils::Exponent,
24}
25
26impl DecryptionKey {
27 pub fn generate(rng: &mut (impl RngCore + CryptoRng)) -> Result<Self, Error> {
31 let p = Integer::generate_safe_prime(rng, 1536);
32 let q = Integer::generate_safe_prime(rng, 1536);
33 Self::from_primes(p, q)
34 }
35
36 #[allow(clippy::many_single_char_names)]
42 pub fn from_primes(p: Integer, q: Integer) -> Result<Self, Error> {
43 if p == q {
45 return Err(Reason::InvalidPQ.into());
46 }
47 let pm1 = &p - 1u8;
48 let qm1 = &q - 1u8;
49 let ek = EncryptionKey::from_n(&p * &q);
50 let lambda = pm1.lcm_ref(&qm1);
51 if lambda.cmp0().is_eq() {
52 return Err(Reason::InvalidPQ.into());
53 }
54
55 let u = lambda.invert_ref(ek.n()).ok_or(Reason::InvalidPQ)?;
57
58 let crt_mod_nn = utils::CrtExp::build_nn(&p, &q).ok_or(Reason::BuildFastExp)?;
59 let exp_n = crt_mod_nn.prepare_exponent(ek.n());
60 let exp_lambda = crt_mod_nn.prepare_exponent(&lambda);
61
62 Ok(Self {
63 ek,
64 lambda,
65 mu: u,
66 p,
67 q,
68 crt_mod_nn,
69 exp_n,
70 exp_lambda,
71 })
72 }
73
74 pub fn decrypt(&self, c: &Ciphertext) -> Result<Plaintext, Error> {
76 if !c.in_mult_group_of(self.ek.nn()) {
77 return Err(Reason::Decrypt.into());
78 }
79
80 let a = self
82 .crt_mod_nn
83 .exp(c, &self.exp_lambda)
84 .ok_or(Reason::Decrypt)?;
85
86 let l = self.ek.l(&a).ok_or(Reason::Decrypt)?;
88
89 let plaintext = (l * &self.mu) % self.ek.n();
91
92 if (&plaintext << 1) >= *self.n() {
93 Ok(plaintext - self.n())
94 } else {
95 Ok(plaintext)
96 }
97 }
98
99 pub fn encrypt_with(&self, x: &Plaintext, nonce: &Nonce) -> Result<Ciphertext, Error> {
105 if !self.ek.in_signed_group(x) || !nonce.in_mult_group_of(self.n()) {
106 return Err(Reason::Encrypt.into());
107 }
108
109 let x = if x.cmp0().is_ge() {
110 x.clone()
111 } else {
112 x + self.n()
113 };
114
115 let a = (Integer::one() + x * self.ek.n()) % self.ek.nn();
117 let b = self
119 .crt_mod_nn
120 .exp(nonce, &self.exp_n)
121 .ok_or(Reason::Encrypt)?;
122
123 Ok((a * b) % self.ek.nn())
124 }
125
126 pub fn encrypt_with_random(
134 &self,
135 rng: &mut (impl RngCore + CryptoRng),
136 x: &Plaintext,
137 ) -> Result<(Ciphertext, Nonce), Error> {
138 let nonce = Integer::sample_in_mult_group_of(rng, self.ek.n());
139 let ciphertext = self.encrypt_with(x, &nonce)?;
140 Ok((ciphertext, nonce))
141 }
142
143 pub fn omul(&self, scalar: &Integer, ciphertext: &Ciphertext) -> Result<Ciphertext, Error> {
151 if !scalar.abs_in_mult_group_of(self.n()) || !ciphertext.in_mult_group_of(self.ek.nn()) {
152 return Err(Reason::Ops.into());
153 }
154
155 let e = self.crt_mod_nn.prepare_exponent(scalar);
156 Ok(self.crt_mod_nn.exp(ciphertext, &e).ok_or(Reason::Ops)?)
157 }
158
159 pub fn encryption_key(&self) -> &EncryptionKey {
161 &self.ek
162 }
163
164 pub fn n(&self) -> &Integer {
166 self.ek.n()
167 }
168
169 pub fn lambda(&self) -> &Integer {
171 &self.lambda
172 }
173
174 pub fn mu(&self) -> &Integer {
176 &self.mu
177 }
178
179 pub fn p(&self) -> &Integer {
181 &self.p
182 }
183 pub fn q(&self) -> &Integer {
185 &self.q
186 }
187
188 pub fn bits_length(&self) -> u64 {
190 self.p.significant_bits().min(self.q.significant_bits())
191 }
192}