1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
12 // An implementation of the Blake2b cryptographic hash function.
13 // The implementation closely follows: https://tools.ietf.org/html/rfc7693
15 // "BLAKE2 is a cryptographic hash function faster than MD5, SHA-1, SHA-2, and
16 // SHA-3, yet is at least as secure as the latest standard SHA-3."
17 // according to their own website :)
19 // Indeed this implementation is two to three times as fast as our SHA-256
20 // implementation. If you have the luxury of being able to use crates from
21 // crates.io, you can go there and find still faster implementations.
26 pub struct Blake2bCtx {
35 impl ::std::fmt::Debug for Blake2bCtx {
36 fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
37 try!(write!(fmt, "hash: "));
38 for v in &self.h[..] {
39 try!(write!(fmt, "{:x}", v));
46 fn b2b_g(v: &mut [u64; 16],
54 v[a] = v[a].wrapping_add(v[b]).wrapping_add(x);
55 v[d] = (v[d] ^ v[a]).rotate_right(32);
56 v[c] = v[c].wrapping_add(v[d]);
57 v[b] = (v[b] ^ v[c]).rotate_right(24);
58 v[a] = v[a].wrapping_add(v[b]).wrapping_add(y);
59 v[d] = (v[d] ^ v[a]).rotate_right(16);
60 v[c] = v[c].wrapping_add(v[d]);
61 v[b] = (v[b] ^ v[c]).rotate_right(63);
64 // Initialization vector
65 const BLAKE2B_IV: [u64; 8] = [
66 0x6A09E667F3BCC908, 0xBB67AE8584CAA73B,
67 0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1,
68 0x510E527FADE682D1, 0x9B05688C2B3E6C1F,
69 0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179
72 fn blake2b_compress(ctx: &mut Blake2bCtx, last: bool) {
74 const SIGMA: [[usize; 16]; 12] = [
75 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ],
76 [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ],
77 [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 ],
78 [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 ],
79 [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 ],
80 [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 ],
81 [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 ],
82 [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 ],
83 [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 ],
84 [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 ],
85 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ],
86 [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ]
89 let mut v: [u64; 16] = [
109 v[12] ^= ctx.t[0]; // low 64 bits of offset
110 v[13] ^= ctx.t[1]; // high 64 bits
116 // Re-interpret the input buffer in the state as u64s
117 let m: &mut [u64; 16] = unsafe {
118 let b: &mut [u8; 128] = &mut ctx.b;
119 ::std::mem::transmute(b)
122 // It's OK to modify the buffer in place since this is the last time
123 // this data will be accessed before it's overwritten
124 if cfg!(target_endian = "big") {
125 for word in &mut m[..] {
126 *word = word.to_be();
131 b2b_g(&mut v, 0, 4, 8, 12, m[SIGMA[i][ 0]], m[SIGMA[i][ 1]]);
132 b2b_g(&mut v, 1, 5, 9, 13, m[SIGMA[i][ 2]], m[SIGMA[i][ 3]]);
133 b2b_g(&mut v, 2, 6, 10, 14, m[SIGMA[i][ 4]], m[SIGMA[i][ 5]]);
134 b2b_g(&mut v, 3, 7, 11, 15, m[SIGMA[i][ 6]], m[SIGMA[i][ 7]]);
135 b2b_g(&mut v, 0, 5, 10, 15, m[SIGMA[i][ 8]], m[SIGMA[i][ 9]]);
136 b2b_g(&mut v, 1, 6, 11, 12, m[SIGMA[i][10]], m[SIGMA[i][11]]);
137 b2b_g(&mut v, 2, 7, 8, 13, m[SIGMA[i][12]], m[SIGMA[i][13]]);
138 b2b_g(&mut v, 3, 4, 9, 14, m[SIGMA[i][14]], m[SIGMA[i][15]]);
143 ctx.h[i] ^= v[i] ^ v[i + 8];
147 fn blake2b_new(outlen: usize, key: &[u8]) -> Blake2bCtx {
148 assert!(outlen > 0 && outlen <= 64 && key.len() <= 64);
150 let mut ctx = Blake2bCtx {
155 outlen: outlen as u16,
159 ctx.h[0] ^= 0x01010000 ^ ((key.len() << 8) as u64) ^ (outlen as u64);
162 blake2b_update(&mut ctx, key);
169 fn blake2b_update(ctx: &mut Blake2bCtx, mut data: &[u8]) {
170 assert!(!ctx.finalized, "Blake2bCtx already finalized");
172 let mut bytes_to_copy = data.len();
173 let mut space_in_buffer = ctx.b.len() - ctx.c;
175 while bytes_to_copy > space_in_buffer {
176 checked_mem_copy(data, &mut ctx.b[ctx.c .. ], space_in_buffer);
178 ctx.t[0] = ctx.t[0].wrapping_add(ctx.b.len() as u64);
179 if ctx.t[0] < (ctx.b.len() as u64) {
182 blake2b_compress(ctx, false);
185 data = &data[space_in_buffer .. ];
186 bytes_to_copy -= space_in_buffer;
187 space_in_buffer = ctx.b.len();
190 if bytes_to_copy > 0 {
191 checked_mem_copy(data, &mut ctx.b[ctx.c .. ], bytes_to_copy);
192 ctx.c += bytes_to_copy;
196 fn blake2b_final(ctx: &mut Blake2bCtx)
198 assert!(!ctx.finalized, "Blake2bCtx already finalized");
200 ctx.t[0] = ctx.t[0].wrapping_add(ctx.c as u64);
201 if ctx.t[0] < ctx.c as u64 {
210 blake2b_compress(ctx, true);
212 if cfg!(target_endian = "big") {
213 // Make sure that the data is in memory in little endian format, as is
214 // demanded by BLAKE2
215 for word in &mut ctx.h {
216 *word = word.to_le();
220 ctx.finalized = true;
224 fn checked_mem_copy<T1, T2>(from: &[T1], to: &mut [T2], byte_count: usize) {
225 let from_size = from.len() * mem::size_of::<T1>();
226 let to_size = to.len() * mem::size_of::<T2>();
227 assert!(from_size >= byte_count);
228 assert!(to_size >= byte_count);
229 let from_byte_ptr = from.as_ptr() as * const u8;
230 let to_byte_ptr = to.as_mut_ptr() as * mut u8;
232 ::std::ptr::copy_nonoverlapping(from_byte_ptr, to_byte_ptr, byte_count);
236 pub fn blake2b(out: &mut [u8], key: &[u8], data: &[u8])
238 let mut ctx = blake2b_new(out.len(), key);
239 blake2b_update(&mut ctx, data);
240 blake2b_final(&mut ctx);
241 checked_mem_copy(&ctx.h, out, ctx.outlen as usize);
244 pub struct Blake2bHasher(Blake2bCtx);
246 impl ::std::hash::Hasher for Blake2bHasher {
247 fn write(&mut self, bytes: &[u8]) {
248 blake2b_update(&mut self.0, bytes);
251 fn finish(&self) -> u64 {
252 assert!(self.0.outlen == 8,
253 "Hasher initialized with incompatible output length");
254 u64::from_le(self.0.h[0])
259 pub fn new(outlen: usize, key: &[u8]) -> Blake2bHasher {
260 Blake2bHasher(blake2b_new(outlen, key))
263 pub fn finalize(&mut self) -> &[u8] {
264 if !self.0.finalized {
265 blake2b_final(&mut self.0);
267 debug_assert!(mem::size_of_val(&self.0.h) >= self.0.outlen as usize);
268 let raw_ptr = (&self.0.h[..]).as_ptr() as * const u8;
270 slice::from_raw_parts(raw_ptr, self.0.outlen as usize)
275 impl ::std::fmt::Debug for Blake2bHasher {
276 fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
277 write!(fmt, "{:?}", self.0)
282 fn selftest_seq(out: &mut [u8], seed: u32)
284 let mut a: u32 = 0xDEAD4BADu32.wrapping_mul(seed);
287 for i in 0 .. out.len() {
288 let t: u32 = a.wrapping_add(b);
291 out[i] = ((t >> 24) & 0xFF) as u8;
296 fn blake2b_selftest()
298 use std::hash::Hasher;
300 // grand hash of hash results
301 const BLAKE2B_RES: [u8; 32] = [
302 0xC2, 0x3A, 0x78, 0x00, 0xD9, 0x81, 0x23, 0xBD,
303 0x10, 0xF5, 0x06, 0xC6, 0x1E, 0x29, 0xDA, 0x56,
304 0x03, 0xD7, 0x63, 0xB8, 0xBB, 0xAD, 0x2E, 0x73,
305 0x7F, 0x5E, 0x76, 0x5A, 0x7B, 0xCC, 0xD4, 0x75
309 const B2B_MD_LEN: [usize; 4] = [20, 32, 48, 64];
310 const B2B_IN_LEN: [usize; 6] = [0, 3, 128, 129, 255, 1024];
312 let mut data = [0u8; 1024];
313 let mut md = [0u8; 64];
314 let mut key = [0u8; 64];
316 let mut hasher = Blake2bHasher::new(32, &[]);
319 let outlen = B2B_MD_LEN[i];
321 let inlen = B2B_IN_LEN[j];
323 selftest_seq(&mut data[.. inlen], inlen as u32); // unkeyed hash
324 blake2b(&mut md[.. outlen], &[], &data[.. inlen]);
325 hasher.write(&md[.. outlen]); // hash the hash
327 selftest_seq(&mut key[0 .. outlen], outlen as u32); // keyed hash
328 blake2b(&mut md[.. outlen], &key[.. outlen], &data[.. inlen]);
329 hasher.write(&md[.. outlen]); // hash the hash
333 // compute and compare the hash of hashes
334 let md = hasher.finalize();
336 assert_eq!(md[i], BLAKE2B_RES[i]);