553 lines
18 KiB
Rust
553 lines
18 KiB
Rust
//! Random number generator tests.
|
|
|
|
#![cfg(feature = "rng")]
|
|
|
|
use chacha20::{
|
|
ChaCha8Rng, ChaCha12Rng, ChaCha20Rng, SerializedRngState,
|
|
rand_core::{Rng, SeedableRng},
|
|
};
|
|
use hex_literal::hex;
|
|
|
|
const KEY: [u8; 32] = hex!("0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20");
|
|
const STREAM: u64 = 0xF0F1F2F3_F4F5F6F7;
|
|
const BLOCK_WORDS: u8 = 16;
|
|
|
|
#[test]
|
|
fn test_rng_output() {
|
|
let mut rng = ChaCha20Rng::from_seed(KEY);
|
|
let mut bytes = [0u8; 13];
|
|
|
|
rng.fill_bytes(&mut bytes);
|
|
let expected = hex!("B1697E9FC6461E1983D131CF69");
|
|
assert_eq!(bytes, expected);
|
|
|
|
rng.fill_bytes(&mut bytes);
|
|
let expected = hex!("A7A3FC134F149880E8BB2B5D23");
|
|
assert_eq!(bytes, expected);
|
|
}
|
|
|
|
#[test]
|
|
fn test_chacha_true_values_a() {
|
|
// Test vectors 1 and 2 from
|
|
// https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
|
|
let seed = [0u8; 32];
|
|
let mut rng = ChaCha20Rng::from_seed(seed);
|
|
|
|
let mut results = [0u32; 16];
|
|
for i in results.iter_mut() {
|
|
*i = rng.next_u32();
|
|
}
|
|
let expected = [
|
|
0xade0b876, 0x903df1a0, 0xe56a5d40, 0x28bd8653, 0xb819d2bd, 0x1aed8da0, 0xccef36a8,
|
|
0xc70d778b, 0x7c5941da, 0x8d485751, 0x3fe02477, 0x374ad8b8, 0xf4b8436a, 0x1ca11815,
|
|
0x69b687c3, 0x8665eeb2,
|
|
];
|
|
assert_eq!(results, expected);
|
|
|
|
for i in results.iter_mut() {
|
|
*i = rng.next_u32();
|
|
}
|
|
let expected = [
|
|
0xbee7079f, 0x7a385155, 0x7c97ba98, 0x0d082d73, 0xa0290fcb, 0x6965e348, 0x3e53c612,
|
|
0xed7aee32, 0x7621b729, 0x434ee69c, 0xb03371d5, 0xd539d874, 0x281fed31, 0x45fb0a51,
|
|
0x1f0ae1ac, 0x6f4d794b,
|
|
];
|
|
assert_eq!(results, expected);
|
|
}
|
|
|
|
#[test]
|
|
fn test_chacha_true_values_b() {
|
|
// Test vector 3 from
|
|
// https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
|
|
let seed = hex!("0000000000000000000000000000000000000000000000000000000000000001");
|
|
let mut rng = ChaCha20Rng::from_seed(seed);
|
|
|
|
// Skip block 0
|
|
for _ in 0..16 {
|
|
rng.next_u32();
|
|
}
|
|
|
|
let mut results = [0u32; 16];
|
|
for i in results.iter_mut() {
|
|
*i = rng.next_u32();
|
|
}
|
|
let expected = [
|
|
0x2452eb3a, 0x9249f8ec, 0x8d829d9b, 0xddd4ceb1, 0xe8252083, 0x60818b01, 0xf38422b8,
|
|
0x5aaa49c9, 0xbb00ca8e, 0xda3ba7b4, 0xc4b592d1, 0xfdf2732f, 0x4436274e, 0x2561b3c8,
|
|
0xebdd4aa6, 0xa0136c00,
|
|
];
|
|
assert_eq!(results, expected);
|
|
}
|
|
|
|
#[test]
|
|
fn test_chacha_true_values_c() {
|
|
// Test vector 4 from
|
|
// https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
|
|
let seed = hex!("00FF000000000000000000000000000000000000000000000000000000000000");
|
|
let expected = [
|
|
0xfb4dd572, 0x4bc42ef1, 0xdf922636, 0x327f1394, 0xa78dea8f, 0x5e269039, 0xa1bebbc1,
|
|
0xcaf09aae, 0xa25ab213, 0x48a6b46c, 0x1b9d9bcb, 0x092c5be6, 0x546ca624, 0x1bec45d5,
|
|
0x87f47473, 0x96f0992e,
|
|
];
|
|
let expected_end = 3 * 16;
|
|
let mut results = [0u32; 16];
|
|
|
|
// Test block 2 by skipping block 0 and 1
|
|
let mut rng1 = ChaCha20Rng::from_seed(seed);
|
|
for _ in 0..32 {
|
|
rng1.next_u32();
|
|
}
|
|
for i in results.iter_mut() {
|
|
*i = rng1.next_u32();
|
|
}
|
|
assert_eq!(results, expected);
|
|
assert_eq!(rng1.get_word_pos(), expected_end);
|
|
|
|
// Test block 2 by using `set_word_pos`
|
|
let mut rng2 = ChaCha20Rng::from_seed(seed);
|
|
rng2.set_word_pos(2 * 16);
|
|
for i in results.iter_mut() {
|
|
*i = rng2.next_u32();
|
|
}
|
|
assert_eq!(results, expected);
|
|
assert_eq!(rng2.get_word_pos(), expected_end);
|
|
|
|
// Test block 2 by using `set_block_pos` and u32
|
|
let mut rng3 = ChaCha20Rng::from_seed(seed);
|
|
rng3.set_block_pos(2);
|
|
results = [0u32; 16];
|
|
for i in results.iter_mut() {
|
|
*i = rng3.next_u32();
|
|
}
|
|
assert_eq!(results, expected);
|
|
assert_eq!(rng3.get_word_pos(), expected_end);
|
|
|
|
// Test block 2 by using `set_block_pos` and [u8; 8]
|
|
let mut rng4 = ChaCha20Rng::from_seed(seed);
|
|
rng4.set_block_pos(2);
|
|
let mut buf = [0u8; 8];
|
|
for chunk in expected.chunks_exact(2) {
|
|
rng4.fill_bytes(&mut buf);
|
|
assert_eq!(buf[..4], chunk[0].to_le_bytes());
|
|
assert_eq!(buf[4..], chunk[1].to_le_bytes());
|
|
}
|
|
assert_eq!(rng4.get_word_pos(), expected_end);
|
|
|
|
// Test skipping behaviour with other types
|
|
let mut buf = [0u8; 32];
|
|
rng2.fill_bytes(&mut buf[..]);
|
|
assert_eq!(rng2.get_word_pos(), expected_end + 8);
|
|
rng2.fill_bytes(&mut buf[0..25]);
|
|
assert_eq!(rng2.get_word_pos(), expected_end + 15);
|
|
rng2.next_u64();
|
|
assert_eq!(rng2.get_word_pos(), expected_end + 17);
|
|
rng2.next_u32();
|
|
rng2.next_u64();
|
|
assert_eq!(rng2.get_word_pos(), expected_end + 20);
|
|
rng2.fill_bytes(&mut buf[0..1]);
|
|
assert_eq!(rng2.get_word_pos(), expected_end + 21);
|
|
}
|
|
|
|
#[test]
|
|
fn test_chacha_multiple_blocks() {
|
|
let seed = hex!("0000000001000000020000000300000004000000050000000600000007000000");
|
|
let mut rng = ChaCha20Rng::from_seed(seed);
|
|
|
|
// Store the 17*i-th 32-bit word,
|
|
// i.e., the i-th word of the i-th 16-word block
|
|
let mut results = [0u32; 16];
|
|
for i in results.iter_mut() {
|
|
*i = rng.next_u32();
|
|
for _ in 0..16 {
|
|
rng.next_u32();
|
|
}
|
|
}
|
|
let expected = [
|
|
0xf225c81a, 0x6ab1be57, 0x04d42951, 0x70858036, 0x49884684, 0x64efec72, 0x4be2d186,
|
|
0x3615b384, 0x11cfa18e, 0xd3c50049, 0x75c775f6, 0x434c6530, 0x2c5bad8f, 0x898881dc,
|
|
0x5f1c86d9, 0xc1f8e7f4,
|
|
];
|
|
assert_eq!(results, expected);
|
|
}
|
|
|
|
#[test]
|
|
fn test_chacha_true_bytes() {
|
|
let seed = [0u8; 32];
|
|
let mut rng = ChaCha20Rng::from_seed(seed);
|
|
let mut results = [0u8; 32];
|
|
rng.fill_bytes(&mut results);
|
|
let expected = hex!("76B8E0ADA0F13D90405D6AE55386BD28BDD219B8A08DED1AA836EFCC8B770DC7");
|
|
assert_eq!(results, expected);
|
|
}
|
|
|
|
#[test]
|
|
fn test_chacha_construction() {
|
|
let seed = hex!("0000000000000000010000000000000002000000000000000300000000000000");
|
|
let mut rng1 = ChaCha20Rng::from_seed(seed);
|
|
assert_eq!(rng1.next_u32(), 137206642);
|
|
|
|
assert_eq!(rng1.get_seed(), seed);
|
|
|
|
let mut rng2 = ChaCha20Rng::from_rng(&mut rng1);
|
|
assert_eq!(rng2.next_u32(), 1325750369);
|
|
}
|
|
|
|
#[test]
|
|
fn test_chacha_nonce() {
|
|
use hex_literal::hex;
|
|
// Test vector 5 from
|
|
// https://www.rfc-editor.org/rfc/rfc8439#section-2.3.2
|
|
let seed = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
|
|
let mut rng = ChaCha20Rng::from_seed(seed);
|
|
|
|
rng.set_stream(0x000000004a000000);
|
|
rng.set_block_pos(u64::from_le_bytes(hex!("0000000000000009")));
|
|
|
|
// The test vectors omit the first 64-bytes of the keystream
|
|
let mut discard_first_64 = [0u8; 64];
|
|
rng.fill_bytes(&mut discard_first_64);
|
|
|
|
let mut results = [0u32; 16];
|
|
for i in results.iter_mut() {
|
|
*i = rng.next_u32();
|
|
}
|
|
let expected = [
|
|
0xe4e7f110, 0x15593bd1, 0x1fdd0f50, 0xc47120a3, 0xc7f4d1c7, 0x0368c033, 0x9aaa2204,
|
|
0x4e6cd4c3, 0x466482d2, 0x09aa9f07, 0x05d7c214, 0xa2028bd9, 0xd19c12b5, 0xb94e16de,
|
|
0xe883d0cb, 0x4e3c50a2,
|
|
];
|
|
|
|
assert_eq!(results, expected);
|
|
}
|
|
|
|
#[test]
|
|
fn test_chacha_nonce_2() {
|
|
// Test vector 5 from
|
|
// https://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
|
|
// Although we do not support setting a nonce, we try it here anyway so
|
|
// we can use this test vector.
|
|
let seed = [0u8; 32];
|
|
let mut rng = ChaCha20Rng::from_seed(seed);
|
|
// 96-bit nonce in LE order is: 0,0,0,0, 0,0,0,0, 0,0,0,2
|
|
rng.set_stream(2u64 << (24 + 32));
|
|
|
|
let mut results = [0u32; 16];
|
|
for i in results.iter_mut() {
|
|
*i = rng.next_u32();
|
|
}
|
|
let expected = [
|
|
0x374dc6c2, 0x3736d58c, 0xb904e24a, 0xcd3f93ef, 0x88228b1a, 0x96a4dfb3, 0x5b76ab72,
|
|
0xc727ee54, 0x0e0e978a, 0xf3145c95, 0x1b748ea8, 0xf786c297, 0x99c28f5f, 0x628314e8,
|
|
0x398a19fa, 0x6ded1b53,
|
|
];
|
|
assert_eq!(results, expected);
|
|
}
|
|
|
|
/// Test vector 9 from https://github.com/pyca/cryptography/blob/main/vectors/cryptography_vectors/ciphers/ChaCha20/counter-overflow.txt
|
|
#[test]
|
|
fn counter_wrap_1() {
|
|
let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
|
|
let block_pos = 18446744073709551615;
|
|
assert_eq!(block_pos, u64::MAX);
|
|
rng.set_block_pos(block_pos);
|
|
|
|
let mut output = [0u8; 64 * 3];
|
|
rng.fill_bytes(&mut output);
|
|
let expected = hex!(
|
|
"d7918cd8620cf832532652c04c01a553092cfb32e7b3f2f5467ae9674a2e9eec17368e"
|
|
"c8027a357c0c51e6ea747121fec45284be0f099d2b3328845607b1768976b8e0ada0f1"
|
|
"3d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d77"
|
|
"24e03fb8d84a376a43b8f41518a11cc387b669b2ee65869f07e7be5551387a98ba977c"
|
|
"732d080dcb0f29a048e3656912c6533e32ee7aed29b721769ce64e43d57133b074d839"
|
|
"d531ed1f28510afb45ace10a1f4b794d6f"
|
|
);
|
|
assert_eq!(expected, output);
|
|
}
|
|
|
|
/// Counts how many bytes were incorrect, and returns:
|
|
///
|
|
/// (`index_of_first_incorrect_word`, `num_incorrect_bytes`)
|
|
fn count_incorrect_bytes(expected: &[u8], output: &[u8]) -> (Option<usize>, u32) {
|
|
assert_eq!(expected.len(), output.len());
|
|
let mut num_incorrect_bytes = 0;
|
|
let mut index_of_first_incorrect_word = None;
|
|
expected
|
|
.iter()
|
|
.enumerate()
|
|
.zip(output.iter())
|
|
.for_each(|((i, a), b)| {
|
|
if a.ne(b) {
|
|
if index_of_first_incorrect_word.is_none() {
|
|
index_of_first_incorrect_word = Some(i / 4);
|
|
}
|
|
num_incorrect_bytes += 1;
|
|
}
|
|
});
|
|
(index_of_first_incorrect_word, num_incorrect_bytes)
|
|
}
|
|
|
|
/// Test vector 8 from https://github.com/pyca/cryptography/blob/main/vectors/cryptography_vectors/ciphers/ChaCha20/counter-overflow.txt
|
|
#[test]
|
|
fn counter_overflow_and_diagnostics() {
|
|
let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
|
|
let block_pos = 4294967295;
|
|
assert_eq!(block_pos, u64::from(u32::MAX));
|
|
rng.set_block_pos(4294967295);
|
|
|
|
let mut output = [0u8; 64 * 4];
|
|
rng.fill_bytes(&mut output[..64 * 3]);
|
|
let block_before_overflow = hex!(
|
|
"ace4cd09e294d1912d4ad205d06f95d9c2f2bfcf453e8753f128765b62215f4d92c74f"
|
|
"2f626c6a640c0b1284d839ec81f1696281dafc3e684593937023b58b1d"
|
|
);
|
|
let first_block_after_overflow = hex!(
|
|
"3db41d3aa0d329285de6f225e6e24bd59c9a17006943d5c9b680e3873bdc683a581946"
|
|
"9899989690c281cd17c96159af0682b5b903468a61f50228cf09622b5a"
|
|
);
|
|
let second_block_after_overflow = hex!(
|
|
"46f0f6efee15c8f1b198cb49d92b990867905159440cc723916dc0012826981039ce17"
|
|
"66aa2542b05db3bd809ab142489d5dbfe1273e7399637b4b3213768aaa"
|
|
);
|
|
assert!(
|
|
output[..64].eq(&block_before_overflow),
|
|
"The first parblock was incorrect before overflow, indicating that ChaCha was not implemented correctly for this backend. Check the rounds() fn or the functions that it calls"
|
|
);
|
|
|
|
rng.set_block_pos(u64::from(u32::MAX) - 1);
|
|
let mut skipped_blocks = [0u8; 64 * 3];
|
|
rng.fill_bytes(&mut skipped_blocks);
|
|
rng.fill_bytes(&mut output[64 * 3..]);
|
|
|
|
output.chunks_exact(64).enumerate().skip(1).zip(&[first_block_after_overflow, second_block_after_overflow, second_block_after_overflow]).for_each(|((i, a), b)| {
|
|
let (index_of_first_incorrect_word, num_incorrect_bytes) = count_incorrect_bytes(a, b);
|
|
let msg = if num_incorrect_bytes == 0 {
|
|
"The block was correct and this will not be shown"
|
|
} else if num_incorrect_bytes > 32 {
|
|
"Most of the block was incorrect, indicating an issue with the counter using 32-bit addition towards the beginning of fn rounds()"
|
|
} else if num_incorrect_bytes <= 8 && matches!(index_of_first_incorrect_word, Some(12 | 13)) {
|
|
"When the state was added to the results/res buffer at the end of fn rounds, the counter was probably incremented in 32-bit fashion for this parblock"
|
|
} else {
|
|
// this is probably unreachable in the event of a failed assertion, but it depends on the seed
|
|
"Some of the block was incorrect"
|
|
};
|
|
assert!(a.eq(b), "PARBLOCK #{} uses incorrect counter addition\nDiagnostic = {}\nnum_incorrect_bytes = {}\nindex_of_first_incorrect_word = {:?}", i + 1, msg, num_incorrect_bytes, index_of_first_incorrect_word);
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn test_wrapping_add() {
|
|
let mut rng = ChaCha20Rng::from_seed(KEY);
|
|
// test counter wrapping-add
|
|
rng.set_word_pos((1 << 68) - 65);
|
|
let mut output = [3u8; 1280];
|
|
rng.fill_bytes(&mut output);
|
|
|
|
assert_ne!(output, [0u8; 1280]);
|
|
|
|
assert!(rng.get_word_pos() < 2000);
|
|
assert!(rng.get_word_pos() != 0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_chacha_clone_streams() {
|
|
let seed = [
|
|
0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 7, 0,
|
|
0, 0,
|
|
];
|
|
let mut rng1 = ChaCha20Rng::from_seed(seed);
|
|
let mut rng2 = ChaCha20Rng::from_seed(seed);
|
|
for _ in 0..16 {
|
|
assert_eq!(rng1.next_u64(), rng2.next_u64());
|
|
}
|
|
|
|
rng1.set_stream(51);
|
|
assert_eq!(rng1.get_stream(), 51);
|
|
assert_eq!(rng2.get_stream(), 0);
|
|
let mut fill_1 = [0u8; 7];
|
|
rng1.fill_bytes(&mut fill_1);
|
|
let mut fill_2 = [0u8; 7];
|
|
rng2.fill_bytes(&mut fill_2);
|
|
assert_ne!(fill_1, fill_2);
|
|
for _ in 0..7 {
|
|
assert!(rng1.next_u64() != rng2.next_u64());
|
|
}
|
|
rng2.set_stream(51); // switch part way through block
|
|
for _ in 7..16 {
|
|
assert_ne!(rng1.next_u64(), rng2.next_u64());
|
|
}
|
|
rng1.set_stream(51);
|
|
rng2.set_stream(51);
|
|
for _ in 0..16 {
|
|
assert_eq!(rng1.next_u64(), rng2.next_u64());
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_chacha_word_pos_wrap_exact() {
|
|
let mut rng = ChaCha20Rng::from_seed(Default::default());
|
|
// refilling the buffer in set_word_pos will wrap the block counter to 0
|
|
let last_block = (1 << 68) - u128::from(4 * BLOCK_WORDS);
|
|
rng.set_word_pos(last_block);
|
|
assert_eq!(rng.get_word_pos(), last_block);
|
|
}
|
|
|
|
#[test]
|
|
fn test_chacha_word_pos_wrap_excess() {
|
|
let mut rng = ChaCha20Rng::from_seed(Default::default());
|
|
// refilling the buffer in set_word_pos will wrap the block counter past 0
|
|
let last_block = (1 << 68) - u128::from(BLOCK_WORDS);
|
|
rng.set_word_pos(last_block);
|
|
assert_eq!(rng.get_word_pos(), last_block);
|
|
}
|
|
|
|
#[test]
|
|
fn test_chacha_word_pos_zero() {
|
|
let mut rng = ChaCha20Rng::from_seed(Default::default());
|
|
assert_eq!(rng.get_word_pos(), 0);
|
|
rng.set_word_pos(0);
|
|
assert_eq!(rng.get_word_pos(), 0);
|
|
}
|
|
|
|
#[test]
|
|
#[allow(trivial_casts)]
|
|
fn test_trait_objects() {
|
|
use rand_core::CryptoRng;
|
|
|
|
let seed = Default::default();
|
|
let mut rng1 = ChaCha20Rng::from_seed(seed);
|
|
let rng2 = &mut ChaCha20Rng::from_seed(seed) as &mut dyn CryptoRng;
|
|
for _ in 0..1000 {
|
|
assert_eq!(rng1.next_u64(), rng2.next_u64());
|
|
}
|
|
}
|
|
|
|
/// If this test fails, the backend may not be
|
|
/// performing 64-bit addition.
|
|
#[test]
|
|
fn counter_wrapping_64_bit_counter() {
|
|
let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
|
|
|
|
// get first four blocks and word pos
|
|
let mut first_blocks = [0u8; 64 * 4];
|
|
rng.fill_bytes(&mut first_blocks);
|
|
let first_blocks_end_word_pos = rng.get_word_pos();
|
|
let first_blocks_end_block_counter = rng.get_block_pos();
|
|
|
|
// get first four blocks after wrapping
|
|
rng.set_block_pos(u64::MAX);
|
|
let mut result = [0u8; 64 * 5];
|
|
rng.fill_bytes(&mut result);
|
|
assert_eq!(first_blocks_end_word_pos, rng.get_word_pos());
|
|
assert_eq!(first_blocks_end_block_counter, rng.get_block_pos());
|
|
|
|
if first_blocks[0..64 * 4].ne(&result[64..]) {
|
|
for (i, (a, b)) in first_blocks.iter().zip(result.iter().skip(64)).enumerate() {
|
|
assert!(!a.ne(b), "i = {}\na = {}\nb = {}", i, a, b);
|
|
}
|
|
}
|
|
assert_eq!(&first_blocks[0..64 * 4], &result[64..]);
|
|
}
|
|
|
|
/// If this test fails, the backend may be doing 32-bit addition.
|
|
#[test]
|
|
fn counter_not_wrapping_at_32_bits() {
|
|
let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
|
|
|
|
// get first four blocks and word pos
|
|
let mut first_blocks = [0u8; 64 * 4];
|
|
rng.fill_bytes(&mut first_blocks);
|
|
let first_blocks_end_word_pos = rng.get_word_pos();
|
|
|
|
// get first four blocks after the supposed overflow
|
|
rng.set_block_pos(u64::from(u32::MAX));
|
|
let mut result = [0u8; 64 * 5];
|
|
rng.fill_bytes(&mut result);
|
|
assert_ne!(first_blocks_end_word_pos, rng.get_word_pos());
|
|
assert_eq!(
|
|
rng.get_word_pos(),
|
|
first_blocks_end_word_pos + (1 << 32) * u128::from(BLOCK_WORDS)
|
|
);
|
|
assert_ne!(&first_blocks[0..64 * 4], &result[64..]);
|
|
}
|
|
|
|
#[test]
|
|
fn test_chacha8rng_serde_roundtrip() {
|
|
for skip_words in 0..100 {
|
|
let mut rng = ChaCha8Rng::from_seed(KEY);
|
|
rng.set_stream(STREAM);
|
|
for _ in 0..skip_words {
|
|
let _ = rng.next_u32();
|
|
}
|
|
let state = rng.serialize_state();
|
|
let mut rng2 = ChaCha8Rng::deserialize_state(&state);
|
|
for _ in 0..100 {
|
|
assert_eq!(rng.next_u32(), rng2.next_u32());
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_chacha12rng_serde_roundtrip() {
|
|
for skip_words in 0..100 {
|
|
let mut rng = ChaCha12Rng::from_seed(KEY);
|
|
rng.set_stream(STREAM);
|
|
for _ in 0..skip_words {
|
|
let _ = rng.next_u32();
|
|
}
|
|
let state = rng.serialize_state();
|
|
let mut rng2 = ChaCha12Rng::deserialize_state(&state);
|
|
for _ in 0..100 {
|
|
assert_eq!(rng.next_u32(), rng2.next_u32());
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_chacha20rng_serde_roundtrip() {
|
|
for skip_words in 0..100 {
|
|
let mut rng = ChaCha20Rng::from_seed(KEY);
|
|
rng.set_stream(STREAM);
|
|
for _ in 0..skip_words {
|
|
let _ = rng.next_u32();
|
|
}
|
|
let state = rng.serialize_state();
|
|
let mut rng2 = ChaCha20Rng::deserialize_state(&state);
|
|
for _ in 0..100 {
|
|
assert_eq!(rng.next_u32(), rng2.next_u32());
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_rng_serialized_state_stability() {
|
|
const EXPECTED: SerializedRngState = hex!(
|
|
"0102030405060708090A0B0C0D0E0F10"
|
|
"1112131415161718191A1B1C1D1E1F20"
|
|
"F7F6F5F4F3F2F1F06400000000000000"
|
|
"00"
|
|
);
|
|
let mut rng = ChaCha8Rng::from_seed(KEY);
|
|
rng.set_stream(STREAM);
|
|
for _ in 0..100 {
|
|
let _ = rng.next_u32();
|
|
}
|
|
let state = rng.serialize_state();
|
|
assert_eq!(state, EXPECTED);
|
|
|
|
let mut rng = ChaCha12Rng::from_seed(KEY);
|
|
rng.set_stream(STREAM);
|
|
for _ in 0..100 {
|
|
let _ = rng.next_u32();
|
|
}
|
|
let state = rng.serialize_state();
|
|
assert_eq!(state, EXPECTED);
|
|
|
|
let mut rng = ChaCha20Rng::from_seed(KEY);
|
|
rng.set_stream(STREAM);
|
|
for _ in 0..100 {
|
|
let _ = rng.next_u32();
|
|
}
|
|
let state = rng.serialize_state();
|
|
assert_eq!(state, EXPECTED);
|
|
}
|