blake2b 0.5.2

BLAKE2b hash function
Documentation
pub use blake2xb::{Blake2xb};
pub use buffered::{Blake2b};
pub use hash::{Hash};
pub use parameter_block::{ParameterBlock};

pub mod unbuffered;
pub mod blake2xb;
mod buffered;
mod hash;
mod parameter_block;
mod simd;
mod slice_ext;

pub const IV: [u64; 8] = [
	0x6A09E667F3BCC908, 0xBB67AE8584CAA73B, 0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1,
	0x510E527FADE682D1, 0x9B05688C2B3E6C1F, 0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179
];

pub fn compress(buffer: &[u64; 16], hash: &mut [u64; 8], counter: (u64, u64), f: (u64, u64)) {
	use simd::u64x4;

	const SIGMA: [[usize; 16]; 10] = [
		[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15],
		[14, 10,  4,  8,  9, 15, 13,  6,  1, 12,  0,  2, 11,  7,  5,  3],
		[11,  8, 12,  0,  5,  2, 15, 13, 10, 14,  3,  6,  7,  1,  9,  4],
		[ 7,  9,  3,  1, 13, 12, 11, 14,  2,  6,  5, 10,  4,  0, 15,  8],
		[ 9,  0,  5,  7,  2,  4, 10, 15, 14,  1, 11, 12,  6,  8,  3, 13],
		[ 2, 12,  6, 10,  0, 11,  8,  3,  4, 13,  7,  5, 15, 14,  1,  9],
		[12,  5,  1, 15, 14, 13,  4, 10,  0,  7,  6,  3,  9,  2,  8, 11],
		[13, 11,  7, 14, 12,  1,  3,  9,  5,  0, 15,  4,  8,  6,  2, 10],
		[ 6, 15, 14,  9, 11,  3,  0,  8, 12,  2, 13,  7,  1,  4, 10,  5],
		[10,  2,  8,  4,  7,  6,  1,  5, 15, 11,  9, 14,  3, 12, 13 , 0]
	];

	#[inline(always)]
	fn round(v: &mut [u64x4; 4], buf: &[u64; 16], s: [usize; 16]) {
		#[inline(always)]
		fn quarter_round(v: &mut [u64x4; 4], rd: u64, rb: u64, m: u64x4) {
			v[0] = v[0] + v[1] + m;
			v[3] = (v[3] ^ v[0]).rotate_right(rd);
			v[2] = v[2] + v[3];
			v[1] = (v[1] ^ v[2]).rotate_right(rb);
		}

		#[inline(always)]
		fn shuffle(v: &mut [u64x4; 4]) {
			v[1] = v[1].shuffle_left_1();
			v[2] = v[2].shuffle_left_2();
			v[3] = v[3].shuffle_left_3();
		}

		#[inline(always)]
		fn unshuffle(v: &mut [u64x4; 4]) {
			v[1] = v[1].shuffle_right_1();
			v[2] = v[2].shuffle_right_2();
			v[3] = v[3].shuffle_right_3();
		}

		quarter_round(v, 32, 24, u64x4(buf[s[0]], buf[s[ 2]], buf[s[ 4]], buf[s[ 6]]));
		quarter_round(v, 16, 63, u64x4(buf[s[1]], buf[s[ 3]], buf[s[ 5]], buf[s[ 7]]));
		shuffle(v);
		quarter_round(v, 32, 24, u64x4(buf[s[8]], buf[s[10]], buf[s[12]], buf[s[14]]));
		quarter_round(v, 16, 63, u64x4(buf[s[9]], buf[s[11]], buf[s[13]], buf[s[15]]));
		unshuffle(v);
	}

	let mut v = [
		u64x4(hash[0], hash[1], hash[2], hash[3]),
		u64x4(hash[4], hash[5], hash[6], hash[7]),
		u64x4(IV[0], IV[1], IV[2], IV[3]),
		u64x4(IV[4] ^ counter.0, IV[5] ^ counter.1, IV[6] ^ f.0, IV[7] ^ f.1)
	];

	round(&mut v, buffer, SIGMA[0]);
	round(&mut v, buffer, SIGMA[1]);
	round(&mut v, buffer, SIGMA[2]);
	round(&mut v, buffer, SIGMA[3]);
	round(&mut v, buffer, SIGMA[4]);
	round(&mut v, buffer, SIGMA[5]);
	round(&mut v, buffer, SIGMA[6]);
	round(&mut v, buffer, SIGMA[7]);
	round(&mut v, buffer, SIGMA[8]);
	round(&mut v, buffer, SIGMA[9]);
	round(&mut v, buffer, SIGMA[0]);
	round(&mut v, buffer, SIGMA[1]);

	hash[0] ^= v[0].0 ^ v[2].0;
	hash[1] ^= v[0].1 ^ v[2].1;
	hash[2] ^= v[0].2 ^ v[2].2;
	hash[3] ^= v[0].3 ^ v[2].3;
	hash[4] ^= v[1].0 ^ v[3].0;
	hash[5] ^= v[1].1 ^ v[3].1;
	hash[6] ^= v[1].2 ^ v[3].2;
	hash[7] ^= v[1].3 ^ v[3].3;
}

pub fn blake2b(len: usize, data: &[u8]) -> Hash {
	blake2b_keyed(len, &[], data)
}

pub fn blake2b_keyed(len: usize, key: &[u8], data: &[u8]) -> Hash {
	let mut blake2b = Blake2b::keyed(len, key);
	blake2b.update(data);
	blake2b.finish()
}

pub fn blake2xb(len: Option<u32>, data: &[u8]) -> blake2xb::Iter {
	blake2xb_keyed(len, &[], data)
}

pub fn blake2xb_keyed(len: Option<u32>, key: &[u8], data: &[u8]) -> blake2xb::Iter {
	let mut blake2xb = Blake2xb::keyed(len, key);
	blake2xb.update(data);
	blake2xb.finish()
}

pub fn selftest() -> bool {
	const RESULT: [u8; 32] = [
		0xC2, 0x3A, 0x78, 0x00, 0xD9, 0x81, 0x23, 0xBD,
		0x10, 0xF5, 0x06, 0xC6, 0x1E, 0x29, 0xDA, 0x56,
		0x03, 0xD7, 0x63, 0xB8, 0xBB, 0xAD, 0x2E, 0x73,
		0x7F, 0x5E, 0x76, 0x5A, 0x7B, 0xCC, 0xD4, 0x75
	];

	fn selftest_seq(out: &mut [u8]) {
		let mut a = 0xDEAD4BADu32.wrapping_mul(out.len() as u32);
		let mut b = 1;

		for i in 0..out.len() {
			let t = a.wrapping_add(b);
			a = b;
			b = t;

			out[i] = (t >> 24) as u8;
		}
	}


	let mut data = [0u8; 1024];
	let mut key = [0u8; 64];
	let mut hasher = Blake2b::new(32);

	for &i in &[20, 32, 48, 64] {
		selftest_seq(&mut key[..i]);

		for &j in &[0, 3, 128, 129, 255, 1024] {
			selftest_seq(&mut data[..j]);
			hasher.update(&blake2b(i, &data[..j]));
			hasher.update(&blake2b_keyed(i, &key[..i], &data[..j]));
		}
	}

	*hasher.finish() == RESULT
}