aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml13
-rw-r--r--src/lib.rs2
-rw-r--r--src/test.rs2
-rw-r--r--test_vectors/src/bin/generate.rs25
-rw-r--r--test_vectors/src/lib.rs214
5 files changed, 231 insertions, 25 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 376ee53..629c66d 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -53,3 +53,16 @@ jobs:
toolchain: nightly
override: true
- run: cargo test --benches
+
+ test_vectors:
+ name: test vectors
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v1
+ - uses: actions-rs/toolchain@v1
+ with:
+ toolchain: stable
+ override: true
+ - run: cargo test
+ working-directory: ./test_vectors
diff --git a/src/lib.rs b/src/lib.rs
index 6ee4384..9edcd78 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -625,7 +625,7 @@ pub fn hash(input: &[u8]) -> Hash {
}
/// The keyed hash function.
-pub fn hash_keyed(key: &[u8; KEY_LEN], input: &[u8]) -> Hash {
+pub fn keyed_hash(key: &[u8; KEY_LEN], input: &[u8]) -> Hash {
hash_all_at_once(input, key, KEYED_HASH).root_hash()
}
diff --git a/src/test.rs b/src/test.rs
index 3a59974..9d710d2 100644
--- a/src/test.rs
+++ b/src/test.rs
@@ -265,7 +265,7 @@ fn test_compare_reference_impl() {
let mut expected_out = [0; OUT];
reference_hasher.finalize(&mut expected_out);
- let test_out = crate::hash_keyed(&TEST_KEY, input);
+ let test_out = crate::keyed_hash(&TEST_KEY, input);
assert_eq!(&test_out, array_ref!(expected_out, 0, 32));
let mut hasher = crate::Hasher::new_keyed(&TEST_KEY);
hasher.update(input);
diff --git a/test_vectors/src/bin/generate.rs b/test_vectors/src/bin/generate.rs
index 290d335..9fb8ba4 100644
--- a/test_vectors/src/bin/generate.rs
+++ b/test_vectors/src/bin/generate.rs
@@ -1,24 +1,7 @@
-use serde::Serialize;
-
// A non-multiple of 4 is important, since one possible bug is to fail to emit
// partial words.
const OUTPUT_LEN: usize = 2 * blake3::BLOCK_LEN + 3;
-#[derive(Serialize)]
-struct Cases {
- _comment: &'static str,
- key: &'static str,
- cases: Vec<Case>,
-}
-
-#[derive(Serialize)]
-struct Case {
- input_len: usize,
- hash: String,
- keyed_hash: String,
- derive_key: String,
-}
-
fn main() {
let mut cases = Vec::new();
for &input_len in test_vectors::TEST_CASES {
@@ -40,7 +23,7 @@ fn main() {
.update(&input)
.finalize_xof(&mut derive_key_out);
- cases.push(Case {
+ cases.push(test_vectors::Case {
input_len,
hash: hex::encode(&hash_out[..]),
keyed_hash: hex::encode(&keyed_hash_out[..]),
@@ -48,9 +31,9 @@ fn main() {
});
}
- let output = serde_json::to_string_pretty(&Cases {
- _comment: "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 251-byte-long repeating pattern: 0, 1, 2, ..., 249, 250, 0, 1, ... The key used with keyed_hash and derive_key is the 32-byte ASCII string given 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.",
- key: std::str::from_utf8(test_vectors::TEST_KEY).unwrap(),
+ let output = serde_json::to_string_pretty(&test_vectors::Cases {
+ _comment: "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 251-byte-long repeating pattern: 0, 1, 2, ..., 249, 250, 0, 1, ... The key used with keyed_hash and derive_key is the 32-byte ASCII string given 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.".to_string(),
+ key: std::str::from_utf8(test_vectors::TEST_KEY).unwrap().to_string(),
cases,
}).unwrap();
diff --git a/test_vectors/src/lib.rs b/test_vectors/src/lib.rs
index e38d9f2..51eb595 100644
--- a/test_vectors/src/lib.rs
+++ b/test_vectors/src/lib.rs
@@ -1,4 +1,5 @@
use blake3::CHUNK_LEN;
+use serde::{Deserialize, Serialize};
pub const TEST_CASES: &[usize] = &[
0,
@@ -36,10 +37,219 @@ pub fn paint_test_input(buf: &mut [u8]) {
}
}
+#[derive(Serialize, Deserialize)]
+pub struct Cases {
+ pub _comment: String,
+ pub key: String,
+ pub cases: Vec<Case>,
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct Case {
+ pub input_len: usize,
+ pub hash: String,
+ pub keyed_hash: String,
+ pub derive_key: String,
+}
+
#[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(key);
+ 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(key);
+ 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(&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(&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(key);
+ hasher.update(input);
+ hasher.finalize_xof(&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(&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(&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(key);
+ for &b in input {
+ hasher.update(&[b]);
+ }
+ hasher.finalize_xof(&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()
+ );
+ assert_eq!(
+ &expected_derive_key[..32],
+ blake3::derive_key(key, input).as_bytes()
+ );
+ }
+
#[test]
- fn it_works() {
- assert_eq!(2 + 2, 4);
+ fn run_test_vectors() -> Result<(), Box<dyn std::error::Error>> {
+ let test_vectors_file_path = "./test_vectors.json";
+ let test_vectors_json = std::fs::read_to_string(test_vectors_file_path)?;
+ let cases: Cases = serde_json::from_str(&test_vectors_json)?;
+ let key: &[u8; blake3::KEY_LEN] = cases.key.as_bytes().try_into()?;
+ for case in &cases.cases {
+ let mut input = vec![0; case.input_len];
+ paint_test_input(&mut input);
+ let expected_hash = hex::decode(&case.hash)?;
+ let expected_keyed_hash = hex::decode(&case.keyed_hash)?;
+ let expected_derive_key = hex::decode(&case.derive_key)?;
+
+ 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,
+ );
+ }
+ Ok(())
}
}