aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/BLAKE3/test_vectors/src
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2021-11-04 14:18:54 +0100
committerStefan Boberg <[email protected]>2021-11-04 14:19:05 +0100
commit472569d4a5f2daaef7e234d93b417ccb650be624 (patch)
tree085c33f178855ad5ffe48b01bf99d41516ffa011 /thirdparty/BLAKE3/test_vectors/src
parentMerge branch 'main' of https://github.com/EpicGames/zen (diff)
downloadzen-472569d4a5f2daaef7e234d93b417ccb650be624.tar.xz
zen-472569d4a5f2daaef7e234d93b417ccb650be624.zip
Renamed 3rdparty -> thirdparty for legal compliance
Diffstat (limited to 'thirdparty/BLAKE3/test_vectors/src')
-rw-r--r--thirdparty/BLAKE3/test_vectors/src/lib.rs349
1 files changed, 349 insertions, 0 deletions
diff --git a/thirdparty/BLAKE3/test_vectors/src/lib.rs b/thirdparty/BLAKE3/test_vectors/src/lib.rs
new file mode 100644
index 000000000..04460f668
--- /dev/null
+++ b/thirdparty/BLAKE3/test_vectors/src/lib.rs
@@ -0,0 +1,349 @@
+use blake3::{BLOCK_LEN, CHUNK_LEN};
+use serde::{Deserialize, Serialize};
+
+// A non-multiple of 4 is important, since one possible bug is to fail to emit
+// partial words.
+pub const OUTPUT_LEN: usize = 2 * blake3::BLOCK_LEN + 3;
+
+pub const TEST_CASES: &[usize] = &[
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ BLOCK_LEN - 1,
+ BLOCK_LEN,
+ BLOCK_LEN + 1,
+ 2 * BLOCK_LEN - 1,
+ 2 * BLOCK_LEN,
+ 2 * BLOCK_LEN + 1,
+ CHUNK_LEN - 1,
+ CHUNK_LEN,
+ CHUNK_LEN + 1,
+ 2 * CHUNK_LEN,
+ 2 * CHUNK_LEN + 1,
+ 3 * CHUNK_LEN,
+ 3 * CHUNK_LEN + 1,
+ 4 * CHUNK_LEN,
+ 4 * CHUNK_LEN + 1,
+ 5 * CHUNK_LEN,
+ 5 * CHUNK_LEN + 1,
+ 6 * CHUNK_LEN,
+ 6 * CHUNK_LEN + 1,
+ 7 * CHUNK_LEN,
+ 7 * CHUNK_LEN + 1,
+ 8 * CHUNK_LEN,
+ 8 * CHUNK_LEN + 1,
+ 16 * CHUNK_LEN, // AVX512's bandwidth
+ 31 * CHUNK_LEN, // 16 + 8 + 4 + 2 + 1
+ 100 * CHUNK_LEN, // subtrees larger than MAX_SIMD_DEGREE chunks
+];
+
+pub const TEST_KEY: &[u8; blake3::KEY_LEN] = b"whats the Elvish word for friend";
+pub const TEST_CONTEXT: &str = "BLAKE3 2019-12-27 16:29:52 test vectors context";
+
+const COMMENT: &str = r#"
+Each test is an input length and three outputs, one for each of the hash,
+keyed_hash, and derive_key modes. The input in each case is filled with a
+repeating sequence of 251 bytes: 0, 1, 2, ..., 249, 250, 0, 1, ..., and so on.
+The key used with keyed_hash is the 32-byte ASCII string "whats the Elvish word
+for friend", also given in the `key` field below. The context string used with
+derive_key is the ASCII string "BLAKE3 2019-12-27 16:29:52 test vectors
+context", also given in the `context_string` field below. Outputs are encoded
+as hexadecimal. Each case is an extended output, and implementations should
+also check that the first 32 bytes match their default-length output.
+"#;
+
+// Paint the input with a repeating byte pattern. We use a cycle length of 251,
+// because that's the largets prime number less than 256. This makes it
+// unlikely to swapping any two adjacent input blocks or chunks will give the
+// same answer.
+pub fn paint_test_input(buf: &mut [u8]) {
+ for (i, b) in buf.iter_mut().enumerate() {
+ *b = (i % 251) as u8;
+ }
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+pub struct Cases {
+ pub _comment: String,
+ pub key: String,
+ pub context_string: String,
+ pub cases: Vec<Case>,
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+pub struct Case {
+ pub input_len: usize,
+ pub hash: String,
+ pub keyed_hash: String,
+ pub derive_key: String,
+}
+
+pub fn generate_json() -> String {
+ let mut cases = Vec::new();
+ for &input_len in TEST_CASES {
+ let mut input = vec![0; input_len];
+ paint_test_input(&mut input);
+
+ let mut hash_out = [0; OUTPUT_LEN];
+ blake3::Hasher::new()
+ .update(&input)
+ .finalize_xof()
+ .fill(&mut hash_out);
+
+ let mut keyed_hash_out = [0; OUTPUT_LEN];
+ blake3::Hasher::new_keyed(TEST_KEY)
+ .update(&input)
+ .finalize_xof()
+ .fill(&mut keyed_hash_out);
+
+ let mut derive_key_out = [0; OUTPUT_LEN];
+ blake3::Hasher::new_derive_key(TEST_CONTEXT)
+ .update(&input)
+ .finalize_xof()
+ .fill(&mut derive_key_out);
+
+ cases.push(Case {
+ input_len,
+ hash: hex::encode(&hash_out[..]),
+ keyed_hash: hex::encode(&keyed_hash_out[..]),
+ derive_key: hex::encode(&derive_key_out[..]),
+ });
+ }
+
+ let mut json = serde_json::to_string_pretty(&Cases {
+ _comment: COMMENT.trim().replace("\n", " "),
+ key: std::str::from_utf8(TEST_KEY).unwrap().to_string(),
+ context_string: TEST_CONTEXT.to_string(),
+ cases,
+ })
+ .unwrap();
+
+ // Add a trailing newline.
+ json.push('\n');
+ json
+}
+
+pub fn read_test_vectors_file() -> String {
+ let test_vectors_file_path = "./test_vectors.json";
+ std::fs::read_to_string(test_vectors_file_path).expect("failed to read test_vectors.json")
+}
+
+pub fn parse_test_cases() -> Cases {
+ let json = read_test_vectors_file();
+ serde_json::from_str(&json).expect("failed to parse test_vectors.json")
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use std::convert::TryInto;
+
+ fn test_reference_impl_all_at_once(
+ key: &[u8; blake3::KEY_LEN],
+ input: &[u8],
+ expected_hash: &[u8],
+ expected_keyed_hash: &[u8],
+ expected_derive_key: &[u8],
+ ) {
+ let mut out = vec![0; expected_hash.len()];
+ let mut hasher = reference_impl::Hasher::new();
+ hasher.update(input);
+ hasher.finalize(&mut out);
+ assert_eq!(expected_hash, &out[..]);
+
+ let mut out = vec![0; expected_keyed_hash.len()];
+ let mut hasher = reference_impl::Hasher::new_keyed(key);
+ hasher.update(input);
+ hasher.finalize(&mut out);
+ assert_eq!(expected_keyed_hash, &out[..]);
+
+ let mut out = vec![0; expected_derive_key.len()];
+ let mut hasher = reference_impl::Hasher::new_derive_key(TEST_CONTEXT);
+ hasher.update(input);
+ hasher.finalize(&mut out);
+ assert_eq!(expected_derive_key, &out[..]);
+ }
+
+ fn test_reference_impl_one_at_a_time(
+ key: &[u8; blake3::KEY_LEN],
+ input: &[u8],
+ expected_hash: &[u8],
+ expected_keyed_hash: &[u8],
+ expected_derive_key: &[u8],
+ ) {
+ let mut out = vec![0; expected_hash.len()];
+ let mut hasher = reference_impl::Hasher::new();
+ for &b in input {
+ hasher.update(&[b]);
+ }
+ hasher.finalize(&mut out);
+ assert_eq!(expected_hash, &out[..]);
+
+ let mut out = vec![0; expected_keyed_hash.len()];
+ let mut hasher = reference_impl::Hasher::new_keyed(key);
+ for &b in input {
+ hasher.update(&[b]);
+ }
+ hasher.finalize(&mut out);
+ assert_eq!(expected_keyed_hash, &out[..]);
+
+ let mut out = vec![0; expected_derive_key.len()];
+ let mut hasher = reference_impl::Hasher::new_derive_key(TEST_CONTEXT);
+ for &b in input {
+ hasher.update(&[b]);
+ }
+ hasher.finalize(&mut out);
+ assert_eq!(expected_derive_key, &out[..]);
+ }
+
+ fn test_incremental_all_at_once(
+ key: &[u8; blake3::KEY_LEN],
+ input: &[u8],
+ expected_hash: &[u8],
+ expected_keyed_hash: &[u8],
+ expected_derive_key: &[u8],
+ ) {
+ let mut out = vec![0; expected_hash.len()];
+ let mut hasher = blake3::Hasher::new();
+ hasher.update(input);
+ hasher.finalize_xof().fill(&mut out);
+ assert_eq!(expected_hash, &out[..]);
+ assert_eq!(&expected_hash[..32], hasher.finalize().as_bytes());
+
+ let mut out = vec![0; expected_keyed_hash.len()];
+ let mut hasher = blake3::Hasher::new_keyed(key);
+ hasher.update(input);
+ hasher.finalize_xof().fill(&mut out);
+ assert_eq!(expected_keyed_hash, &out[..]);
+ assert_eq!(&expected_keyed_hash[..32], hasher.finalize().as_bytes());
+
+ let mut out = vec![0; expected_derive_key.len()];
+ let mut hasher = blake3::Hasher::new_derive_key(TEST_CONTEXT);
+ hasher.update(input);
+ hasher.finalize_xof().fill(&mut out);
+ assert_eq!(expected_derive_key, &out[..]);
+ assert_eq!(&expected_derive_key[..32], hasher.finalize().as_bytes());
+ }
+
+ fn test_incremental_one_at_a_time(
+ key: &[u8; blake3::KEY_LEN],
+ input: &[u8],
+ expected_hash: &[u8],
+ expected_keyed_hash: &[u8],
+ expected_derive_key: &[u8],
+ ) {
+ let mut out = vec![0; expected_hash.len()];
+ let mut hasher = blake3::Hasher::new();
+ for &b in input {
+ hasher.update(&[b]);
+ }
+ hasher.finalize_xof().fill(&mut out);
+ assert_eq!(expected_hash, &out[..]);
+ assert_eq!(&expected_hash[..32], hasher.finalize().as_bytes());
+
+ let mut out = vec![0; expected_keyed_hash.len()];
+ let mut hasher = blake3::Hasher::new_keyed(key);
+ for &b in input {
+ hasher.update(&[b]);
+ }
+ hasher.finalize_xof().fill(&mut out);
+ assert_eq!(expected_keyed_hash, &out[..]);
+ assert_eq!(&expected_keyed_hash[..32], hasher.finalize().as_bytes());
+
+ let mut out = vec![0; expected_derive_key.len()];
+ let mut hasher = blake3::Hasher::new_derive_key(TEST_CONTEXT);
+ for &b in input {
+ hasher.update(&[b]);
+ }
+ hasher.finalize_xof().fill(&mut out);
+ assert_eq!(expected_derive_key, &out[..]);
+ assert_eq!(&expected_derive_key[..32], hasher.finalize().as_bytes());
+ }
+
+ fn test_recursive(
+ key: &[u8; blake3::KEY_LEN],
+ input: &[u8],
+ expected_hash: &[u8],
+ expected_keyed_hash: &[u8],
+ expected_derive_key: &[u8],
+ ) {
+ assert_eq!(&expected_hash[..32], blake3::hash(input).as_bytes());
+ assert_eq!(
+ &expected_keyed_hash[..32],
+ &blake3::keyed_hash(key, input).as_bytes()[..],
+ );
+ let mut derive_key_out = vec![0; expected_derive_key.len()];
+ blake3::derive_key(TEST_CONTEXT, input, &mut derive_key_out);
+ assert_eq!(expected_derive_key, &derive_key_out[..],);
+ }
+
+ #[test]
+ fn run_test_vectors() {
+ let cases = parse_test_cases();
+ let key: &[u8; blake3::KEY_LEN] = cases.key.as_bytes().try_into().unwrap();
+ for case in &cases.cases {
+ dbg!(case.input_len);
+ let mut input = vec![0; case.input_len];
+ paint_test_input(&mut input);
+ let expected_hash = hex::decode(&case.hash).unwrap();
+ let expected_keyed_hash = hex::decode(&case.keyed_hash).unwrap();
+ let expected_derive_key = hex::decode(&case.derive_key).unwrap();
+
+ test_reference_impl_all_at_once(
+ key,
+ &input,
+ &expected_hash,
+ &expected_keyed_hash,
+ &expected_derive_key,
+ );
+
+ test_reference_impl_one_at_a_time(
+ key,
+ &input,
+ &expected_hash,
+ &expected_keyed_hash,
+ &expected_derive_key,
+ );
+
+ test_incremental_all_at_once(
+ key,
+ &input,
+ &expected_hash,
+ &expected_keyed_hash,
+ &expected_derive_key,
+ );
+
+ test_incremental_one_at_a_time(
+ key,
+ &input,
+ &expected_hash,
+ &expected_keyed_hash,
+ &expected_derive_key,
+ );
+
+ test_recursive(
+ key,
+ &input,
+ &expected_hash,
+ &expected_keyed_hash,
+ &expected_derive_key,
+ );
+ }
+ }
+
+ #[test]
+ fn test_checked_in_vectors_up_to_date() {
+ // Replace Windows newlines, in case Git is configured to alter
+ // newlines when files are checked out.
+ let json = read_test_vectors_file().replace("\r\n", "\n");
+ if generate_json() != json {
+ panic!("Checked-in test_vectors.json is not up to date. Regenerate with `cargo run --bin generate > ./test_vectors.json`.");
+ }
+ }
+}