use num_bigint_dig::{BigUint, RandBigInt, RandPrime};
use num_traits::{One, Zero};
use rand::{rngs::StdRng, SeedableRng};
#[derive(Debug, Clone)]
pub struct DiffieHellmanParams {
pub p: BigUint,
pub g: BigUint,
}
#[derive(Debug, Clone)]
pub struct DiffieHellmanKeyPair {
pub p: BigUint,
pub g: BigUint,
pub private_key: BigUint,
pub public_key: BigUint,
}
pub struct DHParamsConfig {
pub prime_bits: usize,
pub seed: Option<u64>,
}
pub struct DHKeyGenConfig {
pub seed: Option<u64>,
}
impl DiffieHellmanParams {
pub fn generate(config: &DHParamsConfig) -> Self {
let mut rng = match config.seed {
Some(s) => StdRng::seed_from_u64(s),
None => StdRng::from_entropy(),
};
let p = rng.gen_prime(config.prime_bits);
let g = BigUint::from(2_u64);
DiffieHellmanParams { p, g }
}
pub fn generate_keypair(&self, config: &DHKeyGenConfig) -> DiffieHellmanKeyPair {
let mut rng = match config.seed {
Some(s) => StdRng::seed_from_u64(s),
None => StdRng::from_entropy(),
};
let bitlen = self.p.bits();
let mut a = BigUint::zero();
while a.is_zero() {
a = rng.gen_biguint(bitlen);
if a >= self.p.clone() {
a = &a % (&self.p - BigUint::one());
}
}
let pubkey = self.g.modpow(&a, &self.p);
DiffieHellmanKeyPair {
p: self.p.clone(),
g: self.g.clone(),
private_key: a,
public_key: pubkey,
}
}
}
impl DiffieHellmanKeyPair {
pub fn compute_shared_secret(&self, other_pub: &BigUint) -> BigUint {
other_pub.modpow(&self.private_key, &self.p)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_toy_diffie_hellman() {
let dh_config = DHParamsConfig {
prime_bits: 256,
seed: Some(42),
};
let dh_params = DiffieHellmanParams::generate(&dh_config);
let alice_config = DHKeyGenConfig { seed: Some(100) };
let alice = dh_params.generate_keypair(&alice_config);
let bob_config = DHKeyGenConfig { seed: Some(200) };
let bob = dh_params.generate_keypair(&bob_config);
let alice_secret = alice.compute_shared_secret(&bob.public_key);
let bob_secret = bob.compute_shared_secret(&alice.public_key);
assert_eq!(
alice_secret, bob_secret,
"Diffie-Hellman secrets must match"
);
}
}