use super::*;
use dcrypt_algorithms::ec::p521;
use dcrypt_api::Kem;
use rand::rngs::OsRng;
#[cfg(test)]
mod test_utils {
use dcrypt_common::security::SecretBuffer;
pub fn secret_buffer_from_slice<const N: usize>(slice: &[u8]) -> SecretBuffer<N> {
assert_eq!(slice.len(), N, "Slice length must match SecretBuffer size");
let mut buffer = [0u8; N];
buffer.copy_from_slice(slice);
SecretBuffer::new(buffer)
}
}
#[cfg(test)]
use test_utils::secret_buffer_from_slice;
#[test]
fn test_p521_kem_basic_flow() {
let mut rng = OsRng;
let (recipient_pk, recipient_sk) = EcdhP521::keypair(&mut rng).unwrap();
let (ciphertext, shared_secret_sender) =
EcdhP521::encapsulate(&mut rng, &recipient_pk).unwrap();
let shared_secret_recipient = EcdhP521::decapsulate(&recipient_sk, &ciphertext).unwrap();
assert_eq!(
shared_secret_sender.to_bytes(),
shared_secret_recipient.to_bytes(),
"Shared secrets should match"
);
}
#[test]
fn test_p521_kem_multiple_encapsulations() {
let mut rng = OsRng;
let (recipient_pk, recipient_sk) = EcdhP521::keypair(&mut rng).unwrap();
let (ct1, ss1) = EcdhP521::encapsulate(&mut rng, &recipient_pk).unwrap();
let (ct2, ss2) = EcdhP521::encapsulate(&mut rng, &recipient_pk).unwrap();
assert_ne!(ct1.to_bytes(), ct2.to_bytes());
assert_ne!(ss1.to_bytes(), ss2.to_bytes());
let ss1_dec = EcdhP521::decapsulate(&recipient_sk, &ct1).unwrap();
let ss2_dec = EcdhP521::decapsulate(&recipient_sk, &ct2).unwrap();
assert_eq!(ss1.to_bytes(), ss1_dec.to_bytes());
assert_eq!(ss2.to_bytes(), ss2_dec.to_bytes());
}
#[test]
fn test_p521_kem_invalid_public_key() {
let mut rng = OsRng;
let invalid_pk = EcdhP521PublicKey([0u8; p521::P521_POINT_COMPRESSED_SIZE]);
let result = EcdhP521::encapsulate(&mut rng, &invalid_pk);
assert!(result.is_err());
let mut invalid_pk2 = EcdhP521PublicKey([0xFFu8; p521::P521_POINT_COMPRESSED_SIZE]);
invalid_pk2.0[0] = 0x05;
let result2 = EcdhP521::encapsulate(&mut rng, &invalid_pk2);
assert!(result2.is_err());
}
#[test]
fn test_p521_kem_invalid_ciphertext() {
let mut rng = OsRng;
let (_, recipient_sk) = EcdhP521::keypair(&mut rng).unwrap();
let invalid_ct = EcdhP521Ciphertext([0u8; p521::P521_POINT_COMPRESSED_SIZE]);
let result = EcdhP521::decapsulate(&recipient_sk, &invalid_ct);
assert!(result.is_err());
}
#[test]
fn test_p521_kem_wrong_secret_key() {
let mut rng = OsRng;
let (recipient_pk, _) = EcdhP521::keypair(&mut rng).unwrap();
let (_, wrong_sk) = EcdhP521::keypair(&mut rng).unwrap();
let (ciphertext, shared_secret_sender) =
EcdhP521::encapsulate(&mut rng, &recipient_pk).unwrap();
let shared_secret_wrong = EcdhP521::decapsulate(&wrong_sk, &ciphertext).unwrap();
assert_ne!(
shared_secret_sender.to_bytes(),
shared_secret_wrong.to_bytes(),
"Shared secrets should not match with wrong key"
);
}
mod test_vectors {
use super::*;
#[test]
fn test_p521_kem_known_answer() {
let mut rng = OsRng;
let (pk, sk) = EcdhP521::keypair(&mut rng).unwrap();
for _ in 0..5 {
let (ct, ss_enc) = EcdhP521::encapsulate(&mut rng, &pk).unwrap();
let ss_dec = EcdhP521::decapsulate(&sk, &ct).unwrap();
assert_eq!(ss_enc.to_bytes(), ss_dec.to_bytes());
}
}
#[test]
fn test_p521_kem_edge_cases() {
let mut rng = OsRng;
let recipients: Vec<_> = (0..3)
.map(|_| EcdhP521::keypair(&mut rng).unwrap())
.collect();
for (pk, sk) in &recipients {
let (ct, ss_enc) = EcdhP521::encapsulate(&mut rng, pk).unwrap();
let ss_dec = EcdhP521::decapsulate(sk, &ct).unwrap();
assert_eq!(ss_enc.to_bytes(), ss_dec.to_bytes());
}
}
}
#[test]
fn test_p521_kem_deterministic_shared_secret() {
let mut rng = OsRng;
let (recipient_pk, recipient_sk) = EcdhP521::keypair(&mut rng).unwrap();
let (ciphertext, _) = EcdhP521::encapsulate(&mut rng, &recipient_pk).unwrap();
let ss1 = EcdhP521::decapsulate(&recipient_sk, &ciphertext).unwrap();
let ss2 = EcdhP521::decapsulate(&recipient_sk, &ciphertext).unwrap();
assert_eq!(ss1.to_bytes(), ss2.to_bytes());
}
#[test]
fn test_p521_kem_serialization_roundtrip() {
let mut rng = OsRng;
let (pk, sk) = EcdhP521::keypair(&mut rng).unwrap();
let pk_bytes = pk.to_bytes();
let pk_restored = EcdhP521PublicKey::from_bytes(&pk_bytes).unwrap();
let (ct, ss1) = EcdhP521::encapsulate(&mut rng, &pk_restored).unwrap();
let ss2 = EcdhP521::decapsulate(&sk, &ct).unwrap();
assert_eq!(ss1.to_bytes(), ss2.to_bytes());
}
mod nist_compliance {
use super::*;
#[test]
fn test_p521_point_validation() {
let mut rng = OsRng;
let (_, sk) = EcdhP521::keypair(&mut rng).unwrap();
let mut invalid_ct_bytes = [0u8; p521::P521_POINT_COMPRESSED_SIZE];
invalid_ct_bytes[0] = 0x02; invalid_ct_bytes[1..67].fill(0xFF);
let invalid_ct = EcdhP521Ciphertext(invalid_ct_bytes);
let result = EcdhP521::decapsulate(&sk, &invalid_ct);
assert!(result.is_err());
}
#[test]
fn test_p521_scalar_validation() {
let mut rng = OsRng;
let (pk, _) = EcdhP521::keypair(&mut rng).unwrap();
assert_eq!(pk.to_bytes().len(), p521::P521_POINT_COMPRESSED_SIZE);
}
}
#[test]
fn test_p521_kem_consistency_across_implementations() {
let mut rng = OsRng;
for _ in 0..10 {
let (pk, sk) = EcdhP521::keypair(&mut rng).unwrap();
let (ct, ss_enc) = EcdhP521::encapsulate(&mut rng, &pk).unwrap();
let ss_dec = EcdhP521::decapsulate(&sk, &ct).unwrap();
assert_eq!(
ss_enc.to_bytes(),
ss_dec.to_bytes(),
"Encapsulation and decapsulation must produce same shared secret"
);
assert_eq!(
ss_enc.to_bytes().len(),
p521::P521_KEM_SHARED_SECRET_KDF_OUTPUT_SIZE,
"Shared secret must have correct length"
);
}
}
#[test]
fn test_p521_kem_compressed_format_sizes() {
let mut rng = OsRng;
let (pk, sk) = EcdhP521::keypair(&mut rng).unwrap();
assert_eq!(
pk.to_bytes().len(),
p521::P521_POINT_COMPRESSED_SIZE,
"Public key should be compressed"
);
assert_eq!(
sk.to_bytes().len(),
p521::P521_SCALAR_SIZE,
"Secret key size unchanged"
);
let (ct, _) = EcdhP521::encapsulate(&mut rng, &pk).unwrap();
assert_eq!(
ct.to_bytes().len(),
p521::P521_POINT_COMPRESSED_SIZE,
"Ciphertext should be compressed"
);
}
#[test]
fn test_p521_kem_invalid_compressed_prefix() {
let mut rng = OsRng;
let invalid_prefixes = [0x00, 0x01, 0x04, 0x05, 0xFF];
for prefix in &invalid_prefixes {
let mut invalid_pk_bytes = [0u8; p521::P521_POINT_COMPRESSED_SIZE];
invalid_pk_bytes[0] = *prefix;
invalid_pk_bytes[1..].fill(0x42);
let invalid_pk = EcdhP521PublicKey(invalid_pk_bytes);
let result = EcdhP521::encapsulate(&mut rng, &invalid_pk);
assert!(result.is_err(), "Prefix {:02x} should be rejected", prefix);
}
}
mod p521_specific {
use super::*;
#[test]
fn test_p521_field_element_size() {
assert_eq!(p521::P521_FIELD_ELEMENT_SIZE, 66);
assert_eq!(p521::P521_SCALAR_SIZE, 66);
assert_eq!(p521::P521_POINT_COMPRESSED_SIZE, 67); }
#[test]
fn test_p521_kem_interoperability() {
let mut rng = OsRng;
let keypairs: Vec<_> = (0..3)
.map(|_| EcdhP521::keypair(&mut rng).unwrap())
.collect();
for (i, _) in keypairs.iter().enumerate() {
for (j, (pk_j, sk_j)) in keypairs.iter().enumerate() {
if i != j {
let (ct, ss_enc) = EcdhP521::encapsulate(&mut rng, pk_j).unwrap();
let ss_dec = EcdhP521::decapsulate(sk_j, &ct).unwrap();
assert_eq!(ss_enc.to_bytes(), ss_dec.to_bytes());
}
}
}
}
}
mod nist_cavp_vectors {
use super::*;
#[test]
fn test_p521_kem_interop() {
let mut rng = OsRng;
let (pk1, sk1) = EcdhP521::keypair(&mut rng).unwrap();
let (pk2, sk2) = EcdhP521::keypair(&mut rng).unwrap();
let (ct1, ss1) = EcdhP521::encapsulate(&mut rng, &pk2).unwrap();
let ss1_dec = EcdhP521::decapsulate(&sk2, &ct1).unwrap();
assert_eq!(ss1.to_bytes(), ss1_dec.to_bytes());
let (ct2, ss2) = EcdhP521::encapsulate(&mut rng, &pk1).unwrap();
let ss2_dec = EcdhP521::decapsulate(&sk1, &ct2).unwrap();
assert_eq!(ss2.to_bytes(), ss2_dec.to_bytes());
}
}
#[test]
fn test_p521_kem_cross_consistency() {
let mut rng = OsRng;
let (pk521, sk521) = EcdhP521::keypair(&mut rng).unwrap();
assert_eq!(pk521.to_bytes().len(), p521::P521_POINT_COMPRESSED_SIZE);
assert_eq!(sk521.to_bytes().len(), p521::P521_SCALAR_SIZE);
let (ct, ss) = EcdhP521::encapsulate(&mut rng, &pk521).unwrap();
assert_eq!(ct.to_bytes().len(), p521::P521_POINT_COMPRESSED_SIZE);
assert_eq!(
ss.to_bytes().len(),
p521::P521_KEM_SHARED_SECRET_KDF_OUTPUT_SIZE
);
let ss_dec = EcdhP521::decapsulate(&sk521, &ct).unwrap();
assert_eq!(ss.to_bytes(), ss_dec.to_bytes());
}
#[test]
fn test_p521_public_key_serialization() {
let mut rng = OsRng;
let (pk, _) = EcdhP521::keypair(&mut rng).unwrap();
let bytes = pk.to_bytes();
assert_eq!(bytes.len(), 67);
let restored = EcdhP521PublicKey::from_bytes(&bytes).unwrap();
assert_eq!(pk.to_bytes(), restored.to_bytes());
}
#[test]
fn test_p521_secret_key_serialization() {
let mut rng = OsRng;
let (_, sk) = EcdhP521::keypair(&mut rng).unwrap();
let bytes = sk.to_bytes();
assert_eq!(bytes.len(), 66);
let restored = EcdhP521SecretKey::from_bytes(&bytes).unwrap();
let pk1 = ec_p521::scalar_mult_base_g(
&ec_p521::Scalar::from_secret_buffer(secret_buffer_from_slice::<66>(&sk.to_bytes()))
.unwrap(),
)
.unwrap();
let pk2 = ec_p521::scalar_mult_base_g(
&ec_p521::Scalar::from_secret_buffer(secret_buffer_from_slice::<66>(&restored.to_bytes()))
.unwrap(),
)
.unwrap();
assert_eq!(pk1.serialize_compressed(), pk2.serialize_compressed());
}
#[test]
fn test_p521_ciphertext_serialization() {
let mut rng = OsRng;
let (pk, _) = EcdhP521::keypair(&mut rng).unwrap();
let (ct, _) = EcdhP521::encapsulate(&mut rng, &pk).unwrap();
let bytes = ct.to_bytes();
assert_eq!(bytes.len(), 67);
let restored = EcdhP521Ciphertext::from_bytes(&bytes).unwrap();
assert_eq!(ct.to_bytes(), restored.to_bytes());
}
#[test]
fn test_p521_shared_secret_size() {
let mut rng = OsRng;
let (pk, sk) = EcdhP521::keypair(&mut rng).unwrap();
let (ct, ss) = EcdhP521::encapsulate(&mut rng, &pk).unwrap();
assert_eq!(ss.to_bytes().len(), 64);
let ss_dec = EcdhP521::decapsulate(&sk, &ct).unwrap();
assert_eq!(ss_dec.to_bytes().len(), 64);
}
#[test]
fn test_p521_invalid_public_key() {
assert!(EcdhP521PublicKey::from_bytes(&[0u8; 66]).is_err());
assert!(EcdhP521PublicKey::from_bytes(&[0u8; 68]).is_err());
assert!(EcdhP521PublicKey::from_bytes(&[0u8; 67]).is_err());
}
#[test]
fn test_p521_invalid_secret_key() {
assert!(EcdhP521SecretKey::from_bytes(&[0u8; 65]).is_err());
assert!(EcdhP521SecretKey::from_bytes(&[0u8; 67]).is_err());
}
#[test]
fn test_p521_full_kem_with_serialization() {
let mut rng = OsRng;
let (pk, sk) = EcdhP521::keypair(&mut rng).unwrap();
let pk_bytes = pk.to_bytes();
let sk_bytes = sk.to_bytes();
let pk_restored = EcdhP521PublicKey::from_bytes(&pk_bytes).unwrap();
let sk_restored = EcdhP521SecretKey::from_bytes(&sk_bytes).unwrap();
let (ct, ss1) = EcdhP521::encapsulate(&mut rng, &pk_restored).unwrap();
let ct_bytes = ct.to_bytes();
let ct_restored = EcdhP521Ciphertext::from_bytes(&ct_bytes).unwrap();
let ss2 = EcdhP521::decapsulate(&sk_restored, &ct_restored).unwrap();
assert_eq!(ss1.to_bytes(), ss2.to_bytes());
}