1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
use {Hash, ParameterBlock, compress};
use slice_ext::{SliceExt};

#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub struct Blake2b {
	hash: [u64; 8],
	#[cfg(i128)]
	counter: u128,
	#[cfg(not(i128))]
	counter: (u64, u64),
	len: usize
}

impl Blake2b {
	pub fn new(len: usize) -> Self {
		Self::with_parameter_block(len, ParameterBlock::new().set_digest_len(len as u8).set_fanout(1).set_max_depth(1))
	}

	pub fn with_parameter_block(len: usize, parameter_block: ParameterBlock) -> Self {
		assert!(len >= 1 && len <= 64, "len must be >= 1 and <= 64");

		Blake2b {
			hash: parameter_block.xor_with_iv().0,
			counter: (0, 0),
			len: len
		}
	}

	pub fn len(&self) -> usize {
		self.len
	}

	pub fn update(&mut self, block: &[u64; 16]) {
		#[cfg(i128)]
		self.counter.checked_add(128).expect("blake2b counter overflowed");
		#[cfg(not(i128))]
		self.add_counter(128);

		compress(block, &mut self.hash, self.counter, (0, 0));
	}

	pub fn finish(mut self, block: &[u64; 16], len: usize) -> Hash {
		assert!(len <= 128);
		debug_assert!(block.as_bytes()[len..].iter().all(|&i| i == 0));

		#[cfg(i128)]
		self.counter.checked_add(len as u128).expect("blake2b counter overflowed");
		#[cfg(not(i128))]
		self.add_counter(len as u64);

		compress(block, &mut self.hash, self.counter, (!0, 0));
		Hash::new(self.hash, self.len)
	}

	#[cfg(not(i128))]
	fn add_counter(&mut self, v: u64) {
		debug_assert!(v <= 128);

		let (v, b) = self.counter.0.overflowing_add(v);
		self.counter.0 = v;
		if b {
			self.counter.1 = self.counter.1.checked_add(1).expect("blake2b counter overflowed");
		}
	}
}

impl Default for Blake2b {
	fn default() -> Self {
		Self::new(64)
	}
}