use chacha20::cipher::{KeyIvInit, StreamCipher, StreamCipherSeek};
use fast_chacha::FastChaCha20;
use rand::RngCore;
#[cfg(feature = "std")]
use std::time::Instant;
#[test]
fn compare_chacha20_vs_fast_chacha() {
let use_asm = fast_chacha::is_asm_available();
let mut rng = rand::rng();
let mut key = [0u8; 32];
let mut nonce = [0u8; 12];
rng.fill_bytes(&mut key);
rng.fill_bytes(&mut nonce);
let mut plain = Box::new([0u8; 1024 * 1024]);
rng.fill_bytes(&mut plain[..]);
let mut data_std = plain.clone();
let mut data_fast = plain.clone();
let mut data_fallback = plain.clone();
let mut data_6 = plain.clone();
#[cfg(feature = "std")]
let start = Instant::now();
let mut std_cipher = chacha20::ChaCha20::new((&key).into(), (&nonce).into());
std_cipher.seek(64);
std_cipher.apply_keystream(&mut data_std[..]);
#[cfg(feature = "std")]
let std_time = start.elapsed();
#[cfg(feature = "std")]
let start = Instant::now();
let mut fast_cipher = FastChaCha20::new(&key, &nonce);
fast_cipher.seek(64);
if use_asm {
fast_cipher.apply_keystream(&mut data_fast[..]);
} else {
fast_cipher.apply_keystream_pure(&mut data_fast[..], 10);
}
#[cfg(feature = "std")]
let fast_time = start.elapsed();
#[cfg(feature = "std")]
let start = Instant::now();
let mut fallback_cipher = FastChaCha20::new(&key, &nonce);
fallback_cipher.seek(64);
fallback_cipher.apply_keystream_pure(&mut data_fallback[..], 10);
#[cfg(feature = "std")]
let fallback_time = start.elapsed();
#[cfg(feature = "std")]
let start = Instant::now();
let mut chacha6_cipher = FastChaCha20::new(&key, &nonce);
chacha6_cipher.seek(64);
chacha6_cipher.apply_keystream_pure(&mut data_6[..], 3);
#[cfg(feature = "std")]
{
let chacha6_time = start.elapsed();
println!("chacha20 (RustCrypto)\t: {:?}", std_time);
println!("fast_chacha ({:?})\t: {:?}", if use_asm { "ASM" } else { "Fallback" }, fast_time);
println!("fast_chacha (Fallback)\t: {:?}", fallback_time);
println!("chacha6 (Fallback)\t: {:?}", chacha6_time);
}
assert!(
data_std[..] == data_fast[..],
"Result data (Fast vs RustCrypto) is not equal. Algorithms are not compatible."
);
assert!(
data_std[..] == data_fallback[..],
"Result data (Fallback vs RustCrypto) is not equal. Algorithms are not compatible."
);
assert!(
data_fallback[..] == data_fast[..],
"Result data (Fallback vs Fast) is not equal. Algorithms are not compatible."
);
let mut fast_cipher_dec = FastChaCha20::new(&key, &nonce);
fast_cipher_dec.seek(64);
if use_asm {
fast_cipher_dec.apply_keystream(&mut data_fast[..]);
} else {
fast_cipher_dec.apply_keystream_pure(&mut data_fast[..], 10);
}
assert!(data_fast[..] == plain[..], "Decrypted data is not equal to original data.");
}