use anyhow::Result;
use rand::Rng;
#[derive(Debug)]
pub struct DHParticipant {
pub private_key: u64,
pub public_key: u64,
pub shared_secret: Option<u64>,
pub prime: u64,
pub generator: u64,
}
const DH_PRIME: u64 = 2147483647; const DH_GENERATOR: u64 = 2;
impl Default for DHParticipant {
fn default() -> Self {
Self::new()
}
}
impl DHParticipant {
pub fn new() -> Self {
let mut rng = rand::rng();
let private_key = rng.random_range(2..1000000);
let public_key = mod_exp(DH_GENERATOR, private_key, DH_PRIME);
DHParticipant {
private_key,
public_key,
shared_secret: None,
prime: DH_PRIME,
generator: DH_GENERATOR,
}
}
#[allow(dead_code)]
pub fn with_private_key(private_key: u64) -> Self {
let public_key = mod_exp(DH_GENERATOR, private_key, DH_PRIME);
DHParticipant {
private_key,
public_key,
shared_secret: None,
prime: DH_PRIME,
generator: DH_GENERATOR,
}
}
pub fn compute_shared_secret(&mut self, other_public_key: u64) -> Result<u64> {
if other_public_key >= self.prime {
return Err(anyhow::anyhow!("Invalid public key: too large"));
}
let shared_secret = mod_exp(other_public_key, self.private_key, self.prime);
self.shared_secret = Some(shared_secret);
Ok(shared_secret)
}
#[allow(dead_code)]
pub fn get_shared_secret(&self) -> Option<u64> {
self.shared_secret
}
}
pub fn key_exchange(mode: &str) -> Result<String> {
match mode.to_lowercase().as_str() {
"interactive" => interactive_key_exchange(),
"manual" => start_manual_key_exchange(),
"demo" => demonstrate_concept(),
_ => Err(anyhow::anyhow!(
"Invalid mode. Use 'interactive', 'manual', or 'demo'"
)),
}
}
pub fn interactive_key_exchange() -> Result<String> {
println!("\n🔑 Diffie-Hellman Key Exchange Simulation");
println!("==========================================");
let mut alice = DHParticipant::new();
println!("\n👩 Alice (You):");
println!(" Prime (p): {}", alice.prime);
println!(" Generator (g): {}", alice.generator);
println!(" Private key: {} (keep secret!)", alice.private_key);
println!(" Public key: {} (share with Bob)", alice.public_key);
let mut bob = DHParticipant::new();
println!("\n👨 Bob (Simulated):");
println!(" Private key: {} (Bob keeps secret)", bob.private_key);
println!(" Public key: {} (Bob shares with you)", bob.public_key);
let alice_shared = alice.compute_shared_secret(bob.public_key)?;
let bob_shared = bob.compute_shared_secret(alice.public_key)?;
println!("\n🤝 Key Exchange Result:");
println!(" Alice computed shared secret: {alice_shared}");
println!(" Bob computed shared secret: {bob_shared}");
if alice_shared == bob_shared {
println!(" ✅ SUCCESS: Both parties have the same shared secret!");
Ok(format!("Shared secret established: {alice_shared}"))
} else {
println!(" ❌ ERROR: Shared secrets don't match!");
Err(anyhow::anyhow!("Key exchange failed"))
}
}
pub fn start_manual_key_exchange() -> Result<String> {
println!("\n🔑 Diffie-Hellman Manual Key Exchange");
println!("=====================================");
println!("📋 Two-Terminal Testing Instructions:");
println!(" 1. Run this command in Terminal 1 to get your public key");
println!(" 2. Copy the public key and share it with Terminal 2");
println!(" 3. In Terminal 2, run: ruscrypt exchange --dh");
println!(" 4. Terminal 2 will show their public key");
println!(" 5. Use complete_manual_key_exchange() with the other terminal's public key");
println!();
let participant = DHParticipant::new();
println!("🔢 Your DH Parameters:");
println!(" Prime (p): {}", participant.prime);
println!(" Generator (g): {}", participant.generator);
println!();
println!("🔐 Your Keys:");
println!(
" Private key: {} (🚨 KEEP THIS SECRET! 🚨)",
participant.private_key
);
println!(
" Public key: {} (📤 SHARE THIS)",
participant.public_key
);
println!();
println!("📝 Next Steps:");
println!(" 1. Share your public key: {}", participant.public_key);
println!(" 2. Get the other party's public key");
println!(" 3. Run this command to complete the exchange:");
println!(" ruscrypt exchange --dh --complete <other_public_key> <your_private_key>");
println!();
Ok(format!(
"SESSION_DATA: private_key={}, public_key={}, prime={}, generator={}",
participant.private_key, participant.public_key, participant.prime, participant.generator
))
}
pub fn complete_manual_key_exchange(other_public_key: u64, my_private_key: u64) -> Result<String> {
println!("\n🤝 Completing Diffie-Hellman Key Exchange");
println!("==========================================");
let mut my_participant = DHParticipant::with_private_key(my_private_key);
println!("📥 Received Information:");
println!(" Other party's public key: {other_public_key}");
println!(" Your private key: {my_private_key}");
println!(" Your public key: {}", my_participant.public_key);
println!();
let shared_secret = my_participant.compute_shared_secret(other_public_key)?;
println!("🔐 Key Exchange Computation:");
println!(" Formula: shared_secret = other_public_key^my_private_key mod prime");
println!(
" Calculation: {}^{} mod {} = {}",
other_public_key, my_private_key, my_participant.prime, shared_secret
);
println!();
println!("🎉 SHARED SECRET COMPUTED: {shared_secret}");
println!();
println!("✅ Success! Both parties should now have the same shared secret.");
println!("🔒 This shared secret can be used as a key for symmetric encryption.");
Ok(format!("Shared secret: {shared_secret}"))
}
pub fn demonstrate_concept() -> Result<String> {
println!("\n📚 Diffie-Hellman Concept Demonstration");
println!("=======================================");
println!("🎯 This demonstrates the mathematical concepts with small, easy numbers");
println!();
let p = 23; let g = 5;
let alice_private = 6;
let bob_private = 15;
println!("🔢 Public Parameters (known to everyone):");
println!(" Prime (p) = {p}");
println!(" Generator (g) = {g}");
println!();
println!("👩 Alice's Calculations:");
println!(" 1. Chooses private key (a) = {alice_private} (secret)");
let alice_public = mod_exp(g, alice_private, p);
println!(" 2. Computes public key (A) = g^a mod p");
println!(" A = {g}^{alice_private} mod {p} = {alice_public}");
println!(" 3. Sends public key {alice_public} to Bob");
println!();
println!("👨 Bob's Calculations:");
println!(" 1. Chooses private key (b) = {bob_private} (secret)");
let bob_public = mod_exp(g, bob_private, p);
println!(" 2. Computes public key (B) = g^b mod p");
println!(" B = {g}^{bob_private} mod {p} = {bob_public}");
println!(" 3. Sends public key {bob_public} to Alice");
println!();
println!("🤝 Shared Secret Calculation:");
println!(" Alice computes: s = B^a mod p");
let alice_shared = mod_exp(bob_public, alice_private, p);
println!(" Alice: s = {bob_public}^{alice_private} mod {p} = {alice_shared}");
println!();
println!(" Bob computes: s = A^b mod p");
let bob_shared = mod_exp(alice_public, bob_private, p);
println!(" Bob: s = {alice_public}^{bob_private} mod {p} = {bob_shared}");
println!();
if alice_shared == bob_shared {
println!("🎉 SUCCESS: Both parties computed the same shared secret: {alice_shared}");
println!();
println!("🔐 Security Insight:");
println!(" - Public keys {alice_public} and {bob_public} are known to everyone");
println!(" - Private keys {alice_private} and {bob_private} are kept secret");
println!(" - Shared secret {alice_shared} can only be computed by Alice and Bob");
println!(" - An eavesdropper would need to solve the discrete logarithm problem");
Ok(format!(
"Concept demonstration complete. Shared secret: {alice_shared}"
))
} else {
Err(anyhow::anyhow!("Mathematical error in demonstration"))
}
}
fn mod_exp(base: u64, exp: u64, modulus: u64) -> u64 {
if modulus == 1 {
return 0;
}
let mut result = 1;
let mut base = base % modulus;
let mut exp = exp;
while exp > 0 {
if exp % 2 == 1 {
result = (result * base) % modulus;
}
exp >>= 1;
base = (base * base) % modulus;
}
result
}