use crate::{
generate::{calculate_bounds, generate_prime},
size::KeySize,
two, Components,
};
use num_bigint::{prime::probably_prime, BigUint, RandBigInt};
use num_traits::One;
use signature::rand_core::CryptoRngCore;
const MR_ROUNDS: usize = 64;
pub fn common(
rng: &mut impl CryptoRngCore,
KeySize { l, n }: KeySize,
) -> (BigUint, BigUint, BigUint) {
let (p_min, p_max) = calculate_bounds(l);
let (q_min, q_max) = calculate_bounds(n);
let (p, q) = 'gen_pq: loop {
let q = generate_prime(n as usize, rng);
if q < q_min || q > q_max {
continue;
}
for _ in 0..4096 {
let m = 'gen_m: loop {
let m = rng.gen_biguint(l as usize);
if m > p_min && m < p_max {
break 'gen_m m;
}
};
let mr = &m % (two() * &q);
let p = m - mr + BigUint::one();
if probably_prime(&p, MR_ROUNDS) {
break 'gen_pq (p, q);
}
}
};
let e = (&p - BigUint::one()) / &q;
let mut h = BigUint::one();
let g = loop {
let g = h.modpow(&e, &p);
if !g.is_one() {
break g;
}
h += BigUint::one();
};
(p, q, g)
}
#[inline]
pub fn public(components: &Components, x: &BigUint) -> BigUint {
let p = components.p();
let g = components.g();
g.modpow(x, p)
}