rsa/algorithms/
generate.rs1use alloc::vec::Vec;
4use num_bigint::{BigUint, RandPrime};
5#[allow(unused_imports)]
6use num_traits::Float;
7use num_traits::Zero;
8use rand_core::CryptoRngCore;
9
10use crate::{
11 algorithms::rsa::{compute_modulus, compute_private_exponent_euler_totient},
12 errors::{Error, Result},
13};
14
15pub struct RsaPrivateKeyComponents {
16 pub n: BigUint,
17 pub e: BigUint,
18 pub d: BigUint,
19 pub primes: Vec<BigUint>,
20}
21
22pub(crate) fn generate_multi_prime_key_with_exp<R: CryptoRngCore + ?Sized>(
34 rng: &mut R,
35 nprimes: usize,
36 bit_size: usize,
37 exp: &BigUint,
38) -> Result<RsaPrivateKeyComponents> {
39 if nprimes < 2 {
40 return Err(Error::NprimesTooSmall);
41 }
42
43 if bit_size < 64 {
44 let prime_limit = (1u64 << (bit_size / nprimes) as u64) as f64;
45
46 let mut pi = prime_limit / (prime_limit.ln() - 1f64);
48 pi /= 4f64;
50 pi /= 2f64;
53
54 if pi < nprimes as f64 {
55 return Err(Error::TooFewPrimes);
56 }
57 }
58
59 let mut primes = vec![BigUint::zero(); nprimes];
60 let n_final: BigUint;
61 let d_final: BigUint;
62
63 'next: loop {
64 let mut todo = bit_size;
65 if nprimes >= 7 {
77 todo += (nprimes - 2) / 5;
78 }
79
80 for (i, prime) in primes.iter_mut().enumerate() {
81 *prime = rng.gen_prime(todo / (nprimes - i));
82 todo -= prime.bits();
83 }
84
85 for (i, prime1) in primes.iter().enumerate() {
87 for prime2 in primes.iter().take(i) {
88 if prime1 == prime2 {
89 continue 'next;
90 }
91 }
92 }
93
94 let n = compute_modulus(&primes);
95
96 if n.bits() != bit_size {
97 continue 'next;
101 }
102
103 if let Ok(d) = compute_private_exponent_euler_totient(&primes, exp) {
104 n_final = n;
105 d_final = d;
106 break;
107 }
108 }
109
110 Ok(RsaPrivateKeyComponents {
111 n: n_final,
112 e: exp.clone(),
113 d: d_final,
114 primes,
115 })
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121 use num_bigint::BigUint;
122 use num_traits::FromPrimitive;
123 use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
124
125 const EXP: u64 = 65537;
126
127 #[test]
128 fn test_impossible_keys() {
129 let mut rng = ChaCha8Rng::from_seed([42; 32]);
130 let exp = BigUint::from_u64(EXP).expect("invalid static exponent");
131 for i in 0..32 {
132 let _ = generate_multi_prime_key_with_exp(&mut rng, 2, i, &exp);
133 let _ = generate_multi_prime_key_with_exp(&mut rng, 3, i, &exp);
134 let _ = generate_multi_prime_key_with_exp(&mut rng, 4, i, &exp);
135 let _ = generate_multi_prime_key_with_exp(&mut rng, 5, i, &exp);
136 }
137 }
138
139 macro_rules! key_generation {
140 ($name:ident, $multi:expr, $size:expr) => {
141 #[test]
142 fn $name() {
143 let mut rng = ChaCha8Rng::from_seed([42; 32]);
144 let exp = BigUint::from_u64(EXP).expect("invalid static exponent");
145
146 for _ in 0..10 {
147 let components =
148 generate_multi_prime_key_with_exp(&mut rng, $multi, $size, &exp).unwrap();
149 assert_eq!(components.n.bits(), $size);
150 assert_eq!(components.primes.len(), $multi);
151 }
152 }
153 };
154 }
155
156 key_generation!(key_generation_128, 2, 128);
157 key_generation!(key_generation_1024, 2, 1024);
158
159 key_generation!(key_generation_multi_3_256, 3, 256);
160
161 key_generation!(key_generation_multi_4_64, 4, 64);
162
163 key_generation!(key_generation_multi_5_64, 5, 64);
164 key_generation!(key_generation_multi_8_576, 8, 576);
165 key_generation!(key_generation_multi_16_1024, 16, 1024);
166}