use super::*;
const EMPTY_HASH: &str = "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419\
d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce";
const ABC_HASH: &str = "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d1\
7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923";
const ONE_BLOCK_HASH: &str = "865939e120e6805438478841afb739ae4250cf372653078a065cdcfffca4caf7\
98e6d462b65d658fc165782640eded70963449ae1500fb0f24981d7727e22c41";
const THOUSAND_HASH: &str = "1ee4e51ecab5210a518f26150e882627ec839967f19d763e1508b12cfefed148\
58f6a1c9d1f969bc224dc9440f5a6955277e755b9c513f9ba4421c5e50c8d787";
const BLOCK_OF_ONES: &str = "9bcba0ef17a9045ce7f060d2ec5f3616a53d2678dc6462cce9487f34b652c92b\
90ebb8bfedf1bdfd4c94ccad95747ff767399ee51b21a530146c8ca283747890";
const BLOCK_OF_TWOS: &str = "734b5b51a7a03c94f5c7a4ef741dbaf42b1f51414ad170fde7a0c9cc828fecde\
181fcd61b4873ce1e08600fffc33643b3918bde9bf472dc810276e44dec49523";
const BLOCK_OF_THREES: &str = "9061efb74384e444a08131e7860fd28917c7d122b1b52888e0f14637f5f6511a\
9a0a77baa8c588d6f45282fd3a1b5b266e7172ad0c81ddb3a8d410201ede7263";
const BLOCK_OF_FOURS: &str = "05ace7d3ee13e5211b7e22978a690af1cf80ba0772570d5454625d60b7da04e1\
565bb75fd48bf6f1f29bd1f7e672bc9ef2ccc54e66773ab51a9cdf932ff96a8a";
fn compress_one(compress_fn: CompressFn) -> HexString {
let mut state = State::new();
unsafe {
compress_fn(&mut state.h, &[0; BLOCKBYTES], BLOCKBYTES as u128, !0, 0);
}
bytes_to_hex(&state_words_to_bytes(&state.h))
}
fn compress_four(compress_fn: Compress4xFn) -> [HexString; 4] {
let mut state1 = State::new();
let mut state2 = State::new();
let mut state3 = State::new();
let mut state4 = State::new();
unsafe {
compress_fn(
&mut state1.h,
&mut state2.h,
&mut state3.h,
&mut state4.h,
&[1; BLOCKBYTES],
&[2; BLOCKBYTES],
&[3; BLOCKBYTES],
&[4; BLOCKBYTES],
BLOCKBYTES as u128,
BLOCKBYTES as u128,
BLOCKBYTES as u128,
BLOCKBYTES as u128,
!0,
!0,
!0,
!0,
0,
0,
0,
0,
);
}
[
bytes_to_hex(&state_words_to_bytes(&state1.h)),
bytes_to_hex(&state_words_to_bytes(&state2.h)),
bytes_to_hex(&state_words_to_bytes(&state3.h)),
bytes_to_hex(&state_words_to_bytes(&state4.h)),
]
}
#[test]
fn test_all_compression_impls() {
let expected_1 = HexString::from(ONE_BLOCK_HASH).unwrap();
assert_eq!(expected_1, compress_one(portable::compress));
let expected_4 = [
HexString::from(BLOCK_OF_ONES).unwrap(),
HexString::from(BLOCK_OF_TWOS).unwrap(),
HexString::from(BLOCK_OF_THREES).unwrap(),
HexString::from(BLOCK_OF_FOURS).unwrap(),
];
assert_eq!(expected_4, compress_four(portable::compress_4x));
#[cfg(feature = "std")]
{
if is_x86_feature_detected!("avx2") {
assert_eq!(expected_1, compress_one(avx2::compress));
assert_eq!(expected_4, compress_four(avx2::compress_4x));
}
}
}
#[test]
fn test_vectors() {
let io = &[
(&b""[..], EMPTY_HASH),
(&b"abc"[..], ABC_HASH),
(&[0; BLOCKBYTES], ONE_BLOCK_HASH),
(&[0; 1000], THOUSAND_HASH),
];
for &(input, output) in io {
let hash = blake2b(input);
assert_eq!(&hash.to_hex(), output, "hash mismatch");
}
for &(input, output) in io {
let mut state = State::new();
let split = input.len() / 2;
state.update(&input[..split]);
assert_eq!(split as u128, state.count());
state.update(&input[split..]);
assert_eq!(input.len() as u128, state.count());
let hash = state.finalize();
assert_eq!(&hash.to_hex(), output, "hash mismatch");
}
for &(input, output) in io {
let mut state = State::new();
let mut count = 0;
for &b in input {
state.update(&[b]);
count += 1;
assert_eq!(count, state.count());
}
let hash = state.finalize();
assert_eq!(&hash.to_hex(), output, "hash mismatch");
}
}
#[test]
fn test_multiple_finalizes() {
let mut state = State::new();
assert_eq!(&state.finalize().to_hex(), EMPTY_HASH, "hash mismatch");
assert_eq!(&state.finalize().to_hex(), EMPTY_HASH, "hash mismatch");
assert_eq!(&state.finalize().to_hex(), EMPTY_HASH, "hash mismatch");
state.update(b"abc");
assert_eq!(&state.finalize().to_hex(), ABC_HASH, "hash mismatch");
assert_eq!(&state.finalize().to_hex(), ABC_HASH, "hash mismatch");
assert_eq!(&state.finalize().to_hex(), ABC_HASH, "hash mismatch");
}
#[cfg(feature = "std")]
#[test]
fn test_write() {
use std::io::prelude::*;
let mut state = State::new();
state.write_all(&[0; 1000]).unwrap();
let hash = state.finalize();
assert_eq!(&hash.to_hex(), THOUSAND_HASH, "hash mismatch");
}
#[test]
fn test_all_parameters() {
let hash = Params::new()
.hash_length(18)
.key(b"not the real key")
.key(b"bar")
.salt(b"bazbazbazbazbazb")
.personal(b"bing bing bing b")
.fanout(2)
.max_depth(3)
.max_leaf_length(0x04050607)
.node_offset(0x08090a0b0c0d0e0f)
.node_depth(16)
.inner_hash_length(17)
.to_state()
.set_last_node(true)
.update(b"foo")
.finalize();
assert_eq!("ec0f59cb65f92e7fcca1280ba859a6925ded", &hash.to_hex());
}
#[test]
fn test_all_parameters_blake2bp() {
let hash = blake2bp::Params::new()
.hash_length(18)
.key(b"not the real key")
.key(b"bar")
.to_state()
.update(b"foo")
.finalize();
assert_eq!("8c54e888a8a01c63da6585c058fe54ea81df", &hash.to_hex());
}
#[test]
#[should_panic]
fn test_short_hash_length_panics() {
Params::new().hash_length(0);
}
#[test]
#[should_panic]
fn test_long_hash_length_panics() {
Params::new().hash_length(OUTBYTES + 1);
}
#[test]
#[should_panic]
fn test_long_key_panics() {
Params::new().key(&[0; KEYBYTES + 1]);
}
#[test]
#[should_panic]
fn test_long_salt_panics() {
Params::new().salt(&[0; SALTBYTES + 1]);
}
#[test]
#[should_panic]
fn test_long_personal_panics() {
Params::new().personal(&[0; PERSONALBYTES + 1]);
}
#[test]
#[should_panic]
fn test_zero_max_depth_panics() {
Params::new().max_depth(0);
}
#[test]
#[should_panic]
fn test_long_inner_hash_length_panics() {
Params::new().inner_hash_length(OUTBYTES + 1);
}
#[test]
#[should_panic]
fn test_blake2bp_short_hash_length_panics() {
blake2bp::Params::new().hash_length(0);
}
#[test]
#[should_panic]
fn test_blake2bp_long_hash_length_panics() {
blake2bp::Params::new().hash_length(OUTBYTES + 1);
}
#[test]
#[should_panic]
fn test_blake2bp_long_key_panics() {
blake2bp::Params::new().key(&[0; KEYBYTES + 1]);
}
#[test]
fn test_update4() {
const INPUT_PREFIX: &[u8] = b"foobarbaz";
fn test_run(
state0: &mut State,
state1: &mut State,
state2: &mut State,
state3: &mut State,
input0: &[u8],
input1: &[u8],
input2: &[u8],
input3: &[u8],
) {
let expected0 = state0.clone().update(input0).finalize();
let expected1 = state1.clone().update(input1).finalize();
let expected2 = state2.clone().update(input2).finalize();
let expected3 = state3.clone().update(input3).finalize();
update4(
state0, state1, state2, state3, input0, input1, input2, input3,
);
let output = finalize4(state0, state1, state2, state3);
assert_eq!(expected0, output[0]);
assert_eq!(expected1, output[1]);
assert_eq!(expected2, output[2]);
assert_eq!(expected3, output[3]);
}
let mut state_a = State::new();
let mut state_b = State::new();
state_b.set_last_node(true);
let mut state_c = State::new();
state_c.update(INPUT_PREFIX);
let mut state_d = Params::new()
.hash_length(18)
.key(b"bar")
.salt(b"bazbazbazbazbazb")
.personal(b"bing bing bing b")
.fanout(2)
.max_depth(3)
.max_leaf_length(0x04050607)
.node_offset(0x08090a0b0c0d0e0f)
.node_depth(16)
.inner_hash_length(17)
.last_node(true)
.to_state();
let mut input = [0; 35 * BLOCKBYTES];
blake2bp::test::paint_input(&mut input);
let input_e = &input[0_ * BLOCKBYTES..10 * BLOCKBYTES];
let input_f = &input[10 * BLOCKBYTES..20 * BLOCKBYTES];
let input_g = &input[20 * BLOCKBYTES..30 * BLOCKBYTES];
let input_h = &input[30 * BLOCKBYTES..35 * BLOCKBYTES];
for (input0, input1, input2, input3) in &[
(input_e, input_f, input_g, input_h),
(input_f, input_g, input_h, input_e),
(input_g, input_h, input_e, input_f),
(input_h, input_e, input_f, input_g),
] {
test_run(
&mut state_a,
&mut state_b,
&mut state_c,
&mut state_d,
input0,
input1,
input2,
input3,
);
test_run(
&mut state_b,
&mut state_c,
&mut state_d,
&mut state_a,
input0,
input1,
input2,
input3,
);
test_run(
&mut state_c,
&mut state_d,
&mut state_a,
&mut state_b,
input0,
input1,
input2,
input3,
);
test_run(
&mut state_d,
&mut state_a,
&mut state_b,
&mut state_c,
input0,
input1,
input2,
input3,
);
}
}