rsa/algorithms/
generate.rs1use alloc::vec::Vec;
4use crypto_bigint::{BoxedUint, Odd};
5use crypto_primes::{
6 hazmat::{SetBits, SmallFactorsSieveFactory},
7 is_prime, sieve_and_find, Flavor,
8};
9use rand_core::CryptoRng;
10
11use crate::{
12 algorithms::rsa::{compute_modulus, compute_private_exponent_euler_totient},
13 errors::{Error, Result},
14};
15
16pub struct RsaPrivateKeyComponents {
17 pub n: Odd<BoxedUint>,
18 pub e: BoxedUint,
19 pub d: BoxedUint,
20 pub primes: Vec<BoxedUint>,
21}
22
23pub(crate) fn generate_multi_prime_key_with_exp<R: CryptoRng + ?Sized>(
35 rng: &mut R,
36 nprimes: usize,
37 bit_size: usize,
38 exp: BoxedUint,
39) -> Result<RsaPrivateKeyComponents> {
40 if nprimes < 2 {
41 return Err(Error::NprimesTooSmall);
42 }
43
44 if bit_size < 64 {
45 let prime_limit = (1u64 << (bit_size / nprimes) as u64) as f64;
46
47 let mut pi = prime_limit / ((bit_size / nprimes) as f64 * core::f64::consts::LN_2 - 1.);
51
52 pi /= 4f64;
54 pi /= 2f64;
57
58 if pi < nprimes as f64 {
59 return Err(Error::TooFewPrimes);
60 }
61 }
62
63 let mut primes = vec![BoxedUint::zero(); nprimes];
64 let n_final: Odd<BoxedUint>;
65 let d_final: BoxedUint;
66
67 'next: loop {
68 let mut todo = bit_size;
69 if nprimes >= 7 {
81 todo += (nprimes - 2) / 5;
82 }
83
84 for (i, prime) in primes.iter_mut().enumerate() {
85 let bits = (todo / (nprimes - i)) as u32;
86 *prime = generate_prime_with_rng(rng, bits);
87 todo -= prime.bits() as usize;
88 }
89
90 for (i, prime1) in primes.iter().enumerate() {
92 for prime2 in primes.iter().take(i) {
93 if prime1 == prime2 {
94 continue 'next;
95 }
96 }
97 }
98
99 let n = compute_modulus(&primes);
100
101 if n.bits() as usize != bit_size {
102 continue 'next;
106 }
107
108 if let Ok(d) = compute_private_exponent_euler_totient(&primes, &exp) {
109 n_final = n;
110 d_final = d;
111 break;
112 }
113 }
114
115 Ok(RsaPrivateKeyComponents {
116 n: n_final,
117 e: exp,
118 d: d_final,
119 primes,
120 })
121}
122
123fn generate_prime_with_rng<R: CryptoRng + ?Sized>(rng: &mut R, bit_length: u32) -> BoxedUint {
124 let factory = SmallFactorsSieveFactory::new(Flavor::Any, bit_length, SetBits::TwoMsb)
125 .unwrap_or_else(|err| panic!("Error creating the sieve: {err}"));
126
127 sieve_and_find(rng, factory, |_rng, candidate| {
128 is_prime(Flavor::Any, candidate)
129 })
130 .unwrap_or_else(|err| panic!("Error generating random candidates: {}", err))
131 .expect("will produce a result eventually")
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137 use rand::rngs::ChaCha8Rng;
138 use rand_core::SeedableRng;
139
140 const EXP: u64 = 65537;
141
142 #[test]
143 fn test_impossible_keys() {
144 let mut rng = ChaCha8Rng::from_seed([42; 32]);
145 let exp = BoxedUint::from(EXP);
146
147 for i in 0..32 {
148 let _ = generate_multi_prime_key_with_exp(&mut rng, 2, i, exp.clone());
149 let _ = generate_multi_prime_key_with_exp(&mut rng, 3, i, exp.clone());
150 let _ = generate_multi_prime_key_with_exp(&mut rng, 4, i, exp.clone());
151 let _ = generate_multi_prime_key_with_exp(&mut rng, 5, i, exp.clone());
152 }
153 }
154
155 macro_rules! key_generation {
156 ($name:ident, $multi:expr, $size:expr) => {
157 #[test]
158 fn $name() {
159 let mut rng = ChaCha8Rng::from_seed([42; 32]);
160 let exp = BoxedUint::from(EXP);
161 for _ in 0..10 {
162 let components =
163 generate_multi_prime_key_with_exp(&mut rng, $multi, $size, exp.clone())
164 .unwrap();
165 assert_eq!(components.n.bits(), $size);
166 assert_eq!(components.primes.len(), $multi);
167 }
168 }
169 };
170 }
171
172 key_generation!(key_generation_128, 2, 128);
173 key_generation!(key_generation_1024, 2, 1024);
174
175 key_generation!(key_generation_multi_3_256, 3, 256);
176
177 key_generation!(key_generation_multi_4_64, 4, 64);
178
179 key_generation!(key_generation_multi_5_64, 5, 64);
180 key_generation!(key_generation_multi_8_576, 8, 576);
181 }