qssh 0.0.2-alpha

Experimental quantum-safe SSH using post-quantum crypto. Research project - NOT for production. See LIMITATIONS.md
Documentation
use qssh::{PqAlgorithm, crypto::PqKeyExchange};

#[test]
fn test_falcon512_key_exchange() {
    let kex1 = PqKeyExchange::new().expect("Failed to create key exchange");
    let kex2 = PqKeyExchange::new().expect("Failed to create key exchange");
    
    let pub1 = kex1.public_bytes();
    let pub2 = kex2.public_bytes();
    
    assert!(!pub1.is_empty());
    assert!(!pub2.is_empty());
    assert_ne!(pub1, pub2); // Keys should be different
}

#[test]
fn test_falcon_signing() {
    let kex = PqKeyExchange::new().expect("Failed to create key exchange");
    
    let message = b"Test message for signing";
    
    // Test Falcon signing (fast ephemeral)
    let falcon_sig = kex.sign_falcon(message).expect("Failed to sign with Falcon");
    assert!(!falcon_sig.is_empty());
    
    // Test SPHINCS+ signing (long-term identity)
    let sphincs_sig = kex.sign(message).expect("Failed to sign with SPHINCS+");
    assert!(!sphincs_sig.is_empty());
    
    // Signatures should be different
    assert_ne!(falcon_sig, sphincs_sig);
}

#[test]
fn test_key_derivation() {
    use qssh::crypto::kdf::SessionKeyDerivation;
    
    let shared_secret = b"shared secret material";
    let client_random = b"client random";
    let server_random = b"server random";
    
    let keys = SessionKeyDerivation::derive(shared_secret, client_random, server_random);
    
    // Keys should be different
    assert_ne!(&keys.client_to_server_key[..], &keys.server_to_client_key[..]);
    assert_ne!(&keys.client_to_server_key[..], &keys.client_mac_key[..]);
    assert_ne!(&keys.server_to_client_key[..], &keys.server_mac_key[..]);
    
    // Keys should be correct length (32 bytes for ChaCha20)
    assert_eq!(keys.client_to_server_key.len(), 32);
    assert_eq!(keys.server_to_client_key.len(), 32);
    assert_eq!(keys.client_mac_key.len(), 32);
    assert_eq!(keys.server_mac_key.len(), 32);
}

#[test]
fn test_shared_secret_derivation() {
    let kex1 = PqKeyExchange::new().expect("Failed to create key exchange 1");
    let kex2 = PqKeyExchange::new().expect("Failed to create key exchange 2");
    
    let client_random = vec![1u8; 32];
    let server_random = vec![2u8; 32];
    
    // Exchange Falcon shares
    let share1 = kex1.generate_key_share(&client_random).expect("Failed to generate share 1");
    let share2 = kex2.generate_key_share(&server_random).expect("Failed to generate share 2");
    
    // Compute shared secrets
    let secret1 = kex1.compute_shared_secret(&share1, &share2, &client_random, &server_random);
    let secret2 = kex2.compute_shared_secret(&share2, &share1, &client_random, &server_random);
    
    // Both parties should derive the same secret
    assert_eq!(secret1, secret2);
    assert_eq!(secret1.len(), 32); // SHA3-256 output
}

#[cfg(test)]
mod algorithm_tests {
    use super::*;
    
    #[test]
    fn test_algorithm_conversion() {
        // Test algorithm string conversion
        let falcon = PqAlgorithm::Falcon512;
        let sphincs = PqAlgorithm::SphincsPlus;
        
        // Test Display trait
        assert_eq!(falcon.to_string(), "Falcon-512");
        assert_eq!(sphincs.to_string(), "SPHINCS+");
        
        // Basic enum comparison
        assert!(matches!(falcon, PqAlgorithm::Falcon512));
        assert!(matches!(sphincs, PqAlgorithm::SphincsPlus));
    }
    
    #[test]
    fn test_all_algorithms() {
        let algorithms = vec![
            (PqAlgorithm::SphincsPlus, "SPHINCS+"),
            (PqAlgorithm::Kyber512, "Kyber-512"),
            (PqAlgorithm::Kyber768, "Kyber-768"),
            (PqAlgorithm::Kyber1024, "Kyber-1024"),
            (PqAlgorithm::Falcon512, "Falcon-512"),
        ];
        
        for (alg, expected_name) in algorithms {
            assert_eq!(alg.to_string(), expected_name);
        }
    }
}