#![cfg(target_arch = "wasm32")]
#[cfg(test)]
mod tests {
use kyberlib::{decapsulate, encapsulate, keypair, params::*};
use kyberlib_wasm::{Kex, Keys, Params};
use wasm_bindgen_test::*;
wasm_bindgen_test_configure!(run_in_browser);
#[wasm_bindgen_test]
fn test_keypair() {
let mut rng = rand::rngs::OsRng {};
let result = keypair(&mut rng);
assert!(result.is_ok());
}
#[wasm_bindgen_test]
fn test_encapsulate() {
let mut rng = rand::rngs::OsRng {};
let bad_pk =
vec![0u8; KYBER_PUBLIC_KEY_BYTES - 1].into_boxed_slice();
assert!(
encapsulate(&bad_pk, &mut rng).is_err(),
"encap must reject a too-short public key"
);
let valid_len_pk =
vec![0u8; KYBER_PUBLIC_KEY_BYTES].into_boxed_slice();
assert!(
encapsulate(&valid_len_pk, &mut rng).is_ok(),
"encap must accept any length-correct pk byte string"
);
let keys = keypair(&mut rng).expect("keypair must succeed");
assert!(
encapsulate(&keys.public, &mut rng).is_ok(),
"encap must succeed against a freshly-generated pk"
);
}
#[wasm_bindgen_test]
fn test_decapsulate() {
let mut rng = rand::rngs::OsRng {};
let bad_ct =
vec![0u8; KYBER_CIPHERTEXT_BYTES - 1].into_boxed_slice();
let sk = vec![0u8; KYBER_SECRET_KEY_BYTES].into_boxed_slice();
assert!(
decapsulate(&bad_ct, &sk).is_err(),
"decap must reject a too-short ciphertext"
);
let valid_len_ct =
vec![0u8; KYBER_CIPHERTEXT_BYTES].into_boxed_slice();
let ss = decapsulate(&valid_len_ct, &sk)
.expect("implicit rejection must NOT surface an error");
assert_eq!(
ss.len(),
KYBER_SHARED_SECRET_BYTES,
"implicit-rejection output is still 32 bytes"
);
let keys = keypair(&mut rng).expect("keypair must succeed");
let (ct, ss_sender) = encapsulate(&keys.public, &mut rng)
.expect("encap must succeed");
let ss_receiver =
decapsulate(&ct, &keys.secret).expect("decap must succeed");
assert_eq!(
ss_sender, ss_receiver,
"valid round-trip must recover the same shared secret"
);
}
#[wasm_bindgen_test]
fn test_keys() {
let keys = Keys::new().unwrap_or_else(|_| {
panic!("Failed to create Keys instance")
});
assert_eq!(keys.pubkey().len(), KYBER_PUBLIC_KEY_BYTES);
assert_eq!(keys.secret().len(), KYBER_SECRET_KEY_BYTES);
}
#[wasm_bindgen_test]
fn test_kex() {
let keys = match Keys::new() {
Ok(keys) => keys,
Err(_) => {
return;
}
};
let mut kex = Kex::new(keys.pubkey());
assert_eq!(kex.ciphertext().len(), KYBER_CIPHERTEXT_BYTES);
assert_eq!(kex.sharedSecret().len(), KYBER_SHARED_SECRET_BYTES);
let new_ct =
vec![0u8; KYBER_CIPHERTEXT_BYTES].into_boxed_slice();
let new_ss =
vec![0u8; KYBER_SHARED_SECRET_BYTES].into_boxed_slice();
kex.set_ciphertext(new_ct.clone());
kex.set_sharedSecret(new_ss.clone());
assert_eq!(kex.ciphertext(), new_ct);
assert_eq!(kex.sharedSecret(), new_ss);
}
#[wasm_bindgen_test]
fn test_kex_new() {
let keys = match Keys::new() {
Ok(keys) => keys,
Err(_) => {
return;
}
};
assert_eq!(keys.pubkey().len(), KYBER_PUBLIC_KEY_BYTES);
assert_eq!(keys.secret().len(), KYBER_SECRET_KEY_BYTES);
}
#[wasm_bindgen_test]
fn test_params() {
assert_eq!(Params::publicKeyBytes(), KYBER_PUBLIC_KEY_BYTES);
assert_eq!(Params::secretKeyBytes(), KYBER_SECRET_KEY_BYTES);
assert_eq!(Params::ciphertextBytes(), KYBER_CIPHERTEXT_BYTES);
assert_eq!(
Params::sharedSecretBytes(),
KYBER_SHARED_SECRET_BYTES
);
}
#[wasm_bindgen_test]
fn test_encapsulate_rejects_short_public_key() {
let invalid_pk =
vec![0u8; KYBER_PUBLIC_KEY_BYTES - 1].into_boxed_slice();
let mut rng = rand::rngs::OsRng {};
assert!(
encapsulate(&invalid_pk, &mut rng).is_err(),
"encapsulate must reject a too-short public key"
);
}
#[wasm_bindgen_test]
fn test_decapsulate_mismatched_inputs() {
let alice = match Keys::new() {
Ok(keys) => keys,
Err(_) => return,
};
let kex_for_alice = Kex::new(alice.pubkey());
let eve = match Keys::new() {
Ok(keys) => keys,
Err(_) => return,
};
let eve_ss =
decapsulate(&kex_for_alice.ciphertext(), &eve.secret())
.expect("implicit rejection MUST NOT surface an error");
assert_eq!(
eve_ss.len(),
KYBER_SHARED_SECRET_BYTES,
"implicit-rejection output is still 32 bytes"
);
assert_ne!(
eve_ss.as_ref(),
kex_for_alice.sharedSecret().as_ref(),
"Eve must NOT recover Alice's shared secret (would be \
a confidentiality break)"
);
}
#[wasm_bindgen_test]
fn test_decapsulate_valid_inputs() {
let keys = match Keys::new() {
Ok(keys) => keys,
Err(_) => return,
};
let kex = Kex::new(keys.pubkey());
let result = decapsulate(&kex.ciphertext(), &keys.secret());
assert!(result.is_ok());
}
#[wasm_bindgen_test]
fn test_decapsulate_invalid_ciphertext_size() {
let keys = match Keys::new() {
Ok(keys) => keys,
Err(_) => return,
};
let invalid_ct =
vec![0u8; KYBER_CIPHERTEXT_BYTES - 1].into_boxed_slice();
let result = decapsulate(&invalid_ct, &keys.secret());
assert!(result.is_err());
}
#[wasm_bindgen_test]
fn test_decapsulate_invalid_secret_key_size() {
let keys = match Keys::new() {
Ok(keys) => keys,
Err(_) => return,
};
let kex = Kex::new(keys.pubkey());
let invalid_sk =
vec![0u8; KYBER_SECRET_KEY_BYTES - 1].into_boxed_slice();
let result = decapsulate(&kex.ciphertext(), &invalid_sk);
assert!(result.is_err());
}
#[wasm_bindgen_test]
fn test_keys_methods() {
let keys = match Keys::new() {
Ok(keys) => keys,
Err(_) => return,
};
assert_eq!(keys.pubkey().len(), KYBER_PUBLIC_KEY_BYTES);
assert_eq!(keys.secret().len(), KYBER_SECRET_KEY_BYTES);
}
#[wasm_bindgen_test]
fn test_kex_methods() {
let keys = match Keys::new() {
Ok(keys) => keys,
Err(_) => return,
};
let mut kex = Kex::new(keys.pubkey());
assert_eq!(kex.ciphertext().len(), KYBER_CIPHERTEXT_BYTES);
assert_eq!(kex.sharedSecret().len(), KYBER_SHARED_SECRET_BYTES);
let new_ct =
vec![1u8; KYBER_CIPHERTEXT_BYTES].into_boxed_slice();
let new_ss =
vec![2u8; KYBER_SHARED_SECRET_BYTES].into_boxed_slice();
kex.set_ciphertext(new_ct.clone());
kex.set_sharedSecret(new_ss.clone());
assert_eq!(kex.ciphertext(), new_ct);
assert_eq!(kex.sharedSecret(), new_ss);
}
#[wasm_bindgen_test]
fn test_encapsulate_invalid_rng() {
let keys = match Keys::new() {
Ok(keys) => keys,
Err(_) => return,
};
#[allow(dead_code)]
struct MockRng;
impl rand_core::RngCore for MockRng {
fn next_u32(&mut self) -> u32 {
0
}
fn next_u64(&mut self) -> u64 {
0
}
fn fill_bytes(&mut self, _dest: &mut [u8]) {}
fn try_fill_bytes(
&mut self,
_dest: &mut [u8],
) -> Result<(), rand_core::Error> {
Err(rand_core::Error::from(
core::num::NonZeroU32::new(
rand_core::Error::CUSTOM_START + 1,
)
.unwrap(),
))
}
}
impl rand_core::CryptoRng for MockRng {}
let result = encapsulate(&keys.pubkey(), &mut MockRng);
assert!(result.is_err());
}
}