├── .gitignore ├── clippy.toml ├── Cargo.toml ├── benches ├── blake2b.rs └── blake2s.rs ├── src ├── simdint.rs ├── bytes.rs ├── as_bytes.rs ├── lib.rs ├── simd_opt │ ├── mod.rs │ ├── u32x4.rs │ └── u64x4.rs ├── simdty.rs ├── simdop.rs ├── blake2s.rs ├── simd.rs ├── blake2b.rs └── blake2.rs ├── LICENSE-MIT ├── .travis.yml ├── README.md └── LICENSE-APACHE /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | doc-valid-idents = ["BLAKE2b", "BLAKE2s"] 2 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "blake2-rfc" 3 | version = "0.2.18" 4 | authors = ["Cesar Eduardo Barros "] 5 | description = "A pure Rust implementation of BLAKE2 based on RFC 7693." 6 | documentation = "https://docs.rs/blake2-rfc" 7 | repository = "https://github.com/cesarb/blake2-rfc" 8 | readme = "README.md" 9 | keywords = ["blake2", "blake2b", "blake2s", "hash", "crypto"] 10 | categories = ["cryptography", "no-std"] 11 | license = "MIT OR Apache-2.0" 12 | 13 | [badges] 14 | travis-ci = { repository = "cesarb/blake2-rfc" } 15 | 16 | [features] 17 | default = ["std"] 18 | simd = [] 19 | simd_opt = ["simd"] 20 | simd_asm = ["simd_opt"] 21 | std = [] 22 | 23 | [dependencies] 24 | arrayvec = { version = "0.5.1", default-features = false } 25 | constant_time_eq = "0.1.0" 26 | 27 | [dev-dependencies] 28 | data-encoding = "2.0.0" 29 | -------------------------------------------------------------------------------- /benches/blake2b.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | 3 | extern crate blake2_rfc; 4 | extern crate test; 5 | 6 | use std::iter::repeat; 7 | use std::vec::Vec; 8 | use test::Bencher; 9 | 10 | use blake2_rfc::blake2b::Blake2b; 11 | use blake2_rfc::_selftest_seq as selftest_seq; 12 | 13 | fn bench_blake2b(bytes: usize, b: &mut Bencher) { 14 | let data: Vec = repeat(selftest_seq(1024)) 15 | .flat_map(|v| v) 16 | .take(bytes) 17 | .collect(); 18 | 19 | b.bytes = bytes as u64; 20 | b.iter(|| { 21 | let mut state = Blake2b::default(); 22 | state.update(&data[..]); 23 | state.finalize() 24 | }) 25 | } 26 | 27 | #[bench] fn blake2b_16(b: &mut Bencher) { bench_blake2b(16, b) } 28 | #[bench] fn blake2b_4k(b: &mut Bencher) { bench_blake2b(4096, b) } 29 | #[bench] fn blake2b_64k(b: &mut Bencher) { bench_blake2b(65536, b) } 30 | -------------------------------------------------------------------------------- /benches/blake2s.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | 3 | extern crate blake2_rfc; 4 | extern crate test; 5 | 6 | use std::iter::repeat; 7 | use std::vec::Vec; 8 | use test::Bencher; 9 | 10 | use blake2_rfc::blake2s::Blake2s; 11 | use blake2_rfc::_selftest_seq as selftest_seq; 12 | 13 | fn bench_blake2s(bytes: usize, b: &mut Bencher) { 14 | let data: Vec = repeat(selftest_seq(1024)) 15 | .flat_map(|v| v) 16 | .take(bytes) 17 | .collect(); 18 | 19 | b.bytes = bytes as u64; 20 | b.iter(|| { 21 | let mut state = Blake2s::default(); 22 | state.update(&data[..]); 23 | state.finalize() 24 | }) 25 | } 26 | 27 | #[bench] fn blake2s_16(b: &mut Bencher) { bench_blake2s(16, b) } 28 | #[bench] fn blake2s_4k(b: &mut Bencher) { bench_blake2s(4096, b) } 29 | #[bench] fn blake2s_64k(b: &mut Bencher) { bench_blake2s(65536, b) } 30 | -------------------------------------------------------------------------------- /src/simdint.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 blake2-rfc Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | 8 | #![allow(dead_code)] 9 | 10 | #[cfg(feature = "simd")] 11 | extern "platform-intrinsic" { 12 | pub fn simd_add(x: T, y: T) -> T; 13 | pub fn simd_shl(x: T, y: T) -> T; 14 | pub fn simd_shr(x: T, y: T) -> T; 15 | pub fn simd_xor(x: T, y: T) -> T; 16 | 17 | pub fn simd_shuffle2(v: T, w: T, idx: [u32; 2]) -> U; 18 | pub fn simd_shuffle4(v: T, w: T, idx: [u32; 4]) -> U; 19 | pub fn simd_shuffle8(v: T, w: T, idx: [u32; 8]) -> U; 20 | pub fn simd_shuffle16(v: T, w: T, idx: [u32; 16]) -> U; 21 | pub fn simd_shuffle32(v: T, w: T, idx: [u32; 32]) -> U; 22 | } 23 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 The blake2-rfc Developers 2 | Copyright (c) 2017 Google Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | matrix: 3 | include: 4 | - rust: 1.20.0 5 | env: FEATURES= 6 | - rust: 1.20.0 7 | env: FEATURES=--no-default-features 8 | - rust: stable 9 | env: FEATURES= 10 | - rust: stable 11 | env: FEATURES=--no-default-features 12 | - rust: beta 13 | env: FEATURES= 14 | - rust: beta 15 | env: FEATURES=--no-default-features 16 | - rust: nightly 17 | env: FEATURES= 18 | - rust: nightly 19 | env: FEATURES=--features=simd 20 | - rust: nightly 21 | env: FEATURES=--features=simd_opt 22 | - rust: nightly 23 | env: FEATURES=--features=simd_asm 24 | - rust: nightly 25 | env: 'FEATURES="--no-default-features"' 26 | - rust: nightly 27 | env: 'FEATURES="--no-default-features --features=simd"' 28 | - rust: nightly 29 | env: 'FEATURES="--no-default-features --features=simd_opt"' 30 | - rust: nightly 31 | env: 'FEATURES="--no-default-features --features=simd_asm"' 32 | script: 33 | - cargo build --verbose $FEATURES 34 | - cargo test --verbose $FEATURES 35 | - cargo build --verbose --release $FEATURES 36 | - cargo test --verbose --release $FEATURES 37 | - '[ "$TRAVIS_RUST_VERSION" != "nightly" ] || cargo bench --verbose $FEATURES' 38 | -------------------------------------------------------------------------------- /src/bytes.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 blake2-rfc Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | 8 | //! Operations on byte slices. 9 | 10 | use core::ptr; 11 | 12 | /// Operations on byte slices. 13 | #[cfg_attr(feature = "cargo-clippy", allow(stutter))] 14 | pub trait BytesExt { 15 | /// Set all bytes of this slice to the same value. 16 | /// 17 | /// Equivalent to C's memset(). 18 | fn set_bytes(&mut self, value: u8); 19 | 20 | /// Copy all bytes from a source slice to the start of this slice. 21 | /// 22 | /// Equivalent to C's memcpy(). 23 | fn copy_bytes_from(&mut self, src: &[u8]); 24 | } 25 | 26 | impl BytesExt for [u8] { 27 | #[inline] 28 | fn set_bytes(&mut self, value: u8) { 29 | unsafe { 30 | ptr::write_bytes(self.as_mut_ptr(), value, self.len()); 31 | } 32 | } 33 | 34 | #[inline] 35 | fn copy_bytes_from(&mut self, src: &[u8]) { 36 | assert!(src.len() <= self.len()); 37 | unsafe { 38 | ptr::copy_nonoverlapping(src.as_ptr(), self.as_mut_ptr(), src.len()); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/as_bytes.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 blake2-rfc Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | 8 | use core::mem; 9 | use core::slice; 10 | 11 | pub unsafe trait Safe {} 12 | 13 | pub trait AsBytes { 14 | fn as_bytes(&self) -> &[u8]; 15 | fn as_mut_bytes(&mut self) -> &mut [u8]; 16 | } 17 | 18 | impl AsBytes for [T] { 19 | #[inline] 20 | fn as_bytes(&self) -> &[u8] { 21 | unsafe { 22 | slice::from_raw_parts(self.as_ptr() as *const u8, 23 | self.len() * mem::size_of::()) 24 | } 25 | } 26 | 27 | #[inline] 28 | fn as_mut_bytes(&mut self) -> &mut [u8] { 29 | unsafe { 30 | slice::from_raw_parts_mut(self.as_mut_ptr() as *mut u8, 31 | self.len() * mem::size_of::()) 32 | } 33 | } 34 | } 35 | 36 | unsafe impl Safe for u8 {} 37 | unsafe impl Safe for u16 {} 38 | unsafe impl Safe for u32 {} 39 | unsafe impl Safe for u64 {} 40 | unsafe impl Safe for i8 {} 41 | unsafe impl Safe for i16 {} 42 | unsafe impl Safe for i32 {} 43 | unsafe impl Safe for i64 {} 44 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 blake2-rfc Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | 8 | //! A pure Rust implementation of BLAKE2 based on RFC 7693. 9 | 10 | #![no_std] 11 | 12 | #![warn(missing_docs)] 13 | 14 | #![cfg_attr(feature = "cargo-clippy", warn(clippy_pedantic))] 15 | #![cfg_attr(feature = "cargo-clippy", allow(missing_docs_in_private_items))] 16 | 17 | #![cfg_attr(feature = "simd", feature(platform_intrinsics, repr_simd))] 18 | #![cfg_attr(feature = "simd_opt", feature(cfg_target_feature))] 19 | #![cfg_attr(feature = "simd_asm", feature(asm))] 20 | 21 | #[cfg(feature = "std")] 22 | #[macro_use] 23 | extern crate std; 24 | 25 | extern crate arrayvec; 26 | extern crate constant_time_eq; 27 | 28 | mod as_bytes; 29 | mod bytes; 30 | 31 | mod simdty; 32 | mod simdint; 33 | mod simdop; 34 | mod simd_opt; 35 | mod simd; 36 | 37 | #[macro_use] 38 | mod blake2; 39 | 40 | pub mod blake2b; 41 | pub mod blake2s; 42 | 43 | /// Runs the self-test for both BLAKE2b and BLAKE2s. 44 | #[cold] 45 | pub fn selftest() { 46 | blake2b::selftest(); 47 | blake2s::selftest(); 48 | } 49 | 50 | // Internal export of selftest_seq for the benches, not part of the crate API. 51 | pub use blake2::selftest_seq as _selftest_seq; 52 | -------------------------------------------------------------------------------- /src/simd_opt/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 blake2-rfc Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | 8 | #![allow(unused_macros)] 9 | #![cfg_attr(feature = "cargo-clippy", allow(inline_always))] 10 | 11 | #[cfg(feature = "simd")] 12 | macro_rules! transmute_shuffle { 13 | ($tmp:ident, $shuffle:ident, $vec:expr, $idx:expr) => { 14 | unsafe { 15 | use simdty::$tmp; 16 | use simdint::$shuffle; 17 | use core::mem::transmute; 18 | 19 | let tmp_i: $tmp = transmute($vec); 20 | let tmp_o: $tmp = $shuffle(tmp_i, tmp_i, $idx); 21 | transmute(tmp_o) 22 | } 23 | } 24 | } 25 | 26 | #[cfg(feature = "simd")] pub mod u32x4; 27 | #[cfg(feature = "simd")] pub mod u64x4; 28 | 29 | #[cfg(not(feature = "simd"))] 30 | macro_rules! simd_opt { 31 | ($vec:ident) => { 32 | pub mod $vec { 33 | use simdty::$vec; 34 | 35 | #[inline(always)] 36 | pub fn rotate_right_const(vec: $vec, n: u32) -> $vec { 37 | $vec::new(vec.0.rotate_right(n), 38 | vec.1.rotate_right(n), 39 | vec.2.rotate_right(n), 40 | vec.3.rotate_right(n)) 41 | } 42 | } 43 | } 44 | } 45 | 46 | #[cfg(not(feature = "simd"))] simd_opt!(u32x4); 47 | #[cfg(not(feature = "simd"))] simd_opt!(u64x4); 48 | -------------------------------------------------------------------------------- /src/simd_opt/u32x4.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 blake2-rfc Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | 8 | #![cfg_attr(feature = "cargo-clippy", allow(inline_always))] 9 | 10 | use simdty::u32x4; 11 | 12 | #[cfg(feature = "simd_opt")] 13 | #[inline(always)] 14 | pub fn rotate_right_const(vec: u32x4, n: u32) -> u32x4 { 15 | match n { 16 | 16 => rotate_right_16(vec), 17 | 8 => rotate_right_8(vec), 18 | _ => rotate_right_any(vec, n), 19 | } 20 | } 21 | 22 | #[cfg(not(feature = "simd_opt"))] 23 | #[inline(always)] 24 | pub fn rotate_right_const(vec: u32x4, n: u32) -> u32x4 { 25 | rotate_right_any(vec, n) 26 | } 27 | 28 | #[inline(always)] 29 | fn rotate_right_any(vec: u32x4, n: u32) -> u32x4 { 30 | let r = n as u32; 31 | let l = 32 - r; 32 | 33 | (vec >> u32x4::new(r, r, r, r)) ^ (vec << u32x4::new(l, l, l, l)) 34 | } 35 | 36 | #[cfg(feature = "simd_opt")] 37 | #[inline(always)] 38 | fn rotate_right_16(vec: u32x4) -> u32x4 { 39 | if cfg!(target_feature = "ssse3") { 40 | // pshufb (SSSE3) / vpshufb (AVX2) 41 | transmute_shuffle!(u8x16, simd_shuffle16, vec, 42 | [ 2, 3, 0, 1, 43 | 6, 7, 4, 5, 44 | 10, 11, 8, 9, 45 | 14, 15, 12, 13]) 46 | } else if cfg!(any(target_feature = "sse2", target_feature = "neon")) { 47 | // pshuflw+pshufhw (SSE2) / vrev (NEON) 48 | transmute_shuffle!(u16x8, simd_shuffle8, vec, 49 | [1, 0, 50 | 3, 2, 51 | 5, 4, 52 | 7, 6]) 53 | } else { 54 | rotate_right_any(vec, 16) 55 | } 56 | } 57 | 58 | #[cfg(feature = "simd_opt")] 59 | #[inline(always)] 60 | fn rotate_right_8(vec: u32x4) -> u32x4 { 61 | if cfg!(target_feature = "ssse3") { 62 | // pshufb (SSSE3) / vpshufb (AVX2) 63 | transmute_shuffle!(u8x16, simd_shuffle16, vec, 64 | [ 1, 2, 3, 0, 65 | 5, 6, 7, 4, 66 | 9, 10, 11, 8, 67 | 13, 14, 15, 12]) 68 | } else { 69 | rotate_right_any(vec, 8) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/simdty.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2016 blake2-rfc Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | 8 | #![allow(dead_code)] 9 | #![allow(non_camel_case_types)] 10 | 11 | // https://github.com/rust-lang-nursery/rust-clippy/issues/2453 12 | #![cfg_attr(feature = "cargo-clippy", allow(empty_line_after_outer_attr))] 13 | 14 | use as_bytes::Safe; 15 | 16 | #[cfg(feature = "simd")] 17 | macro_rules! decl_simd { 18 | ($($decl:item)*) => { 19 | $( 20 | #[derive(Clone, Copy, Debug)] 21 | #[repr(simd)] 22 | $decl 23 | )* 24 | } 25 | } 26 | 27 | #[cfg(not(feature = "simd"))] 28 | macro_rules! decl_simd { 29 | ($($decl:item)*) => { 30 | $( 31 | #[derive(Clone, Copy, Debug)] 32 | #[repr(C)] 33 | $decl 34 | )* 35 | } 36 | } 37 | 38 | decl_simd! { 39 | pub struct Simd2(pub T, pub T); 40 | pub struct Simd4(pub T, pub T, pub T, pub T); 41 | pub struct Simd8(pub T, pub T, pub T, pub T, 42 | pub T, pub T, pub T, pub T); 43 | pub struct Simd16(pub T, pub T, pub T, pub T, 44 | pub T, pub T, pub T, pub T, 45 | pub T, pub T, pub T, pub T, 46 | pub T, pub T, pub T, pub T); 47 | pub struct Simd32(pub T, pub T, pub T, pub T, 48 | pub T, pub T, pub T, pub T, 49 | pub T, pub T, pub T, pub T, 50 | pub T, pub T, pub T, pub T, 51 | pub T, pub T, pub T, pub T, 52 | pub T, pub T, pub T, pub T, 53 | pub T, pub T, pub T, pub T, 54 | pub T, pub T, pub T, pub T); 55 | } 56 | 57 | pub type u64x2 = Simd2; 58 | 59 | pub type u32x4 = Simd4; 60 | pub type u64x4 = Simd4; 61 | 62 | pub type u16x8 = Simd8; 63 | pub type u32x8 = Simd8; 64 | 65 | pub type u8x16 = Simd16; 66 | pub type u16x16 = Simd16; 67 | 68 | pub type u8x32 = Simd32; 69 | 70 | #[cfg_attr(feature = "cargo-clippy", allow(inline_always))] 71 | impl Simd4 { 72 | #[inline(always)] 73 | pub fn new(e0: T, e1: T, e2: T, e3: T) -> Self { 74 | Simd4(e0, e1, e2, e3) 75 | } 76 | } 77 | 78 | unsafe impl Safe for Simd2 {} 79 | unsafe impl Safe for Simd4 {} 80 | unsafe impl Safe for Simd8 {} 81 | unsafe impl Safe for Simd16 {} 82 | unsafe impl Safe for Simd32 {} 83 | -------------------------------------------------------------------------------- /src/simdop.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 blake2-rfc Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | 8 | use simdty::{u32x4, u64x4}; 9 | #[cfg(feature = "simd")] use simdint; 10 | 11 | use core::ops::{Add, BitXor, Shl, Shr}; 12 | 13 | macro_rules! impl_ops { 14 | ($vec:ident) => { 15 | impl Add for $vec { 16 | type Output = Self; 17 | 18 | #[cfg(feature = "simd")] 19 | #[inline(always)] 20 | fn add(self, rhs: Self) -> Self::Output { 21 | unsafe { simdint::simd_add(self, rhs) } 22 | } 23 | 24 | #[cfg(not(feature = "simd"))] 25 | #[inline(always)] 26 | fn add(self, rhs: Self) -> Self::Output { 27 | $vec::new(self.0.wrapping_add(rhs.0), 28 | self.1.wrapping_add(rhs.1), 29 | self.2.wrapping_add(rhs.2), 30 | self.3.wrapping_add(rhs.3)) 31 | } 32 | } 33 | 34 | impl BitXor for $vec { 35 | type Output = Self; 36 | 37 | #[cfg(feature = "simd")] 38 | #[inline(always)] 39 | fn bitxor(self, rhs: Self) -> Self::Output { 40 | unsafe { simdint::simd_xor(self, rhs) } 41 | } 42 | 43 | #[cfg(not(feature = "simd"))] 44 | #[inline(always)] 45 | fn bitxor(self, rhs: Self) -> Self::Output { 46 | $vec::new(self.0 ^ rhs.0, 47 | self.1 ^ rhs.1, 48 | self.2 ^ rhs.2, 49 | self.3 ^ rhs.3) 50 | } 51 | } 52 | 53 | impl Shl<$vec> for $vec { 54 | type Output = Self; 55 | 56 | #[cfg(feature = "simd")] 57 | #[inline(always)] 58 | fn shl(self, rhs: Self) -> Self::Output { 59 | unsafe { simdint::simd_shl(self, rhs) } 60 | } 61 | 62 | #[cfg(not(feature = "simd"))] 63 | #[inline(always)] 64 | fn shl(self, rhs: Self) -> Self::Output { 65 | $vec::new(self.0 << rhs.0, 66 | self.1 << rhs.1, 67 | self.2 << rhs.2, 68 | self.3 << rhs.3) 69 | } 70 | } 71 | 72 | impl Shr<$vec> for $vec { 73 | type Output = Self; 74 | 75 | #[cfg(feature = "simd")] 76 | #[inline(always)] 77 | fn shr(self, rhs: Self) -> Self::Output { 78 | unsafe { simdint::simd_shr(self, rhs) } 79 | } 80 | 81 | #[cfg(not(feature = "simd"))] 82 | #[inline(always)] 83 | fn shr(self, rhs: Self) -> Self::Output { 84 | $vec::new(self.0 >> rhs.0, 85 | self.1 >> rhs.1, 86 | self.2 >> rhs.2, 87 | self.3 >> rhs.3) 88 | } 89 | } 90 | } 91 | } 92 | 93 | impl_ops!(u32x4); 94 | impl_ops!(u64x4); 95 | -------------------------------------------------------------------------------- /src/blake2s.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 blake2-rfc Developers 2 | // Copyright 2017 Google Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 7 | // copied, modified, or distributed except according to those terms. 8 | 9 | //! The BLAKE2s hash function. 10 | //! 11 | //! # Examples 12 | //! 13 | //! ``` 14 | //! use blake2_rfc::blake2s::{Blake2s, blake2s}; 15 | //! 16 | //! // Using the convenience function. 17 | //! let hash = blake2s(32, &[], b"The quick brown fox jumps over the lazy dog"); 18 | //! 19 | //! // Using the state context. 20 | //! let mut context = Blake2s::new(32); 21 | //! context.update(b"The quick brown fox jumps over the lazy dog"); 22 | //! let hash = context.finalize(); 23 | //! 24 | //! // Using the convenience function, with a key. 25 | //! let hash = blake2s(32, b"key", b"The quick brown fox jumps over the lazy dog"); 26 | //! 27 | //! // Using the state context, with a key. 28 | //! let mut context = Blake2s::with_key(32, b"key"); 29 | //! context.update(b"The quick brown fox jumps over the lazy dog"); 30 | //! let hash = context.finalize(); 31 | //! ``` 32 | //! 33 | //! The returned hash is a `Blake2sResult`, which can be compared with 34 | //! a byte string (the comparison will take constant time), or converted 35 | //! into a byte string. 36 | 37 | #![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))] 38 | 39 | blake2_impl!(Blake2s, Blake2sResult, blake2s, u32, u32x4, 32, 16, 12, 8, 7, [ 40 | 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 41 | 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19, 42 | ]); 43 | 44 | blake2_selftest_impl!(Blake2s, blake2s, [ 45 | 0x6A, 0x41, 0x1F, 0x08, 0xCE, 0x25, 0xAD, 0xCD, 46 | 0xFB, 0x02, 0xAB, 0xA6, 0x41, 0x45, 0x1C, 0xEC, 47 | 0x53, 0xC5, 0x98, 0xB2, 0x4F, 0x4F, 0xC7, 0x87, 48 | 0xFB, 0xDC, 0x88, 0x79, 0x7F, 0x4C, 0x1D, 0xFE, 49 | ], [ 16, 20, 28, 32 ], [ 0, 3, 64, 65, 255, 1024 ]); 50 | 51 | #[cfg(test)] 52 | mod tests { 53 | #![cfg_attr(feature = "cargo-clippy", allow(result_unwrap_used))] 54 | 55 | extern crate data_encoding; 56 | use self::data_encoding::HEXUPPER; 57 | 58 | use blake2::selftest_seq; 59 | use super::{Blake2s, blake2s}; 60 | 61 | #[test] 62 | fn test_empty() { 63 | assert_eq!(&blake2s(32, &[], b""), &HEXUPPER.decode( 64 | b"69217A3079908094E11121D042354A7C1F55B6482CA1A51E1B250DFD1ED0EEF9") 65 | .unwrap()[..]); 66 | } 67 | 68 | #[test] 69 | fn test_default() { 70 | assert_eq!(&Blake2s::default().finalize(), &HEXUPPER.decode( 71 | b"69217A3079908094E11121D042354A7C1F55B6482CA1A51E1B250DFD1ED0EEF9") 72 | .unwrap()[..]); 73 | } 74 | 75 | #[test] 76 | fn selftest() { 77 | super::selftest(); 78 | } 79 | 80 | #[test] 81 | fn test_split() { 82 | let data = selftest_seq(256); 83 | 84 | let mut ctx = Blake2s::new(32); 85 | ctx.update(&data[..16]); 86 | ctx.update(&data[16..32]); 87 | ctx.update(&data[32..224]); 88 | ctx.update(&data[224..]); 89 | 90 | assert_eq!(&ctx.finalize(), &blake2s(32, &[], &data)); 91 | } 92 | 93 | #[cfg(feature = "std")] 94 | #[test] 95 | fn test_write() { 96 | use std::io::prelude::*; 97 | 98 | let data = selftest_seq(1024); 99 | 100 | let mut ctx = Blake2s::new(32); 101 | ctx.update(&data[..]); 102 | 103 | let mut writer = Blake2s::new(32); 104 | writer.write_all(&data[..]).unwrap(); 105 | 106 | assert_eq!(&writer.finalize(), &ctx.finalize()); 107 | } 108 | 109 | #[cfg_attr(debug_assertions, ignore)] 110 | #[test] 111 | fn test_4g() { 112 | const ZEROS: [u8; 4096] = [0; 4096]; 113 | 114 | let mut state = Blake2s::new(32); 115 | for _ in 0..1048576 { 116 | state.update(&ZEROS); 117 | } 118 | assert_eq!(&state.finalize(), &HEXUPPER.decode( 119 | b"2A8E26830310DA3EF7F7032B7B1AF11B989ABA44A3713A22F539F69BD2CE4A87") 120 | .unwrap()[..]); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/simd.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 blake2-rfc Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | 8 | #![cfg_attr(feature = "cargo-clippy", allow(inline_always))] 9 | 10 | use simd_opt; 11 | 12 | pub use simdty::{u32x4, u64x4}; 13 | 14 | pub trait Vector4: Copy { 15 | fn gather(src: &[T], i0: usize, i1: usize, i2: usize, i3: usize) -> Self; 16 | 17 | fn from_le(self) -> Self; 18 | fn to_le(self) -> Self; 19 | 20 | fn wrapping_add(self, rhs: Self) -> Self; 21 | 22 | fn rotate_right_const(self, n: u32) -> Self; 23 | 24 | fn shuffle_left_1(self) -> Self; 25 | fn shuffle_left_2(self) -> Self; 26 | fn shuffle_left_3(self) -> Self; 27 | 28 | #[inline(always)] fn shuffle_right_1(self) -> Self { self.shuffle_left_3() } 29 | #[inline(always)] fn shuffle_right_2(self) -> Self { self.shuffle_left_2() } 30 | #[inline(always)] fn shuffle_right_3(self) -> Self { self.shuffle_left_1() } 31 | } 32 | 33 | macro_rules! impl_vector4 { 34 | ($vec:ident, $word:ident) => { 35 | impl Vector4<$word> for $vec { 36 | #[inline(always)] 37 | fn gather(src: &[$word], i0: usize, i1: usize, 38 | i2: usize, i3: usize) -> Self { 39 | $vec::new(src[i0], src[i1], src[i2], src[i3]) 40 | } 41 | 42 | #[cfg(target_endian = "little")] 43 | #[inline(always)] 44 | fn from_le(self) -> Self { self } 45 | 46 | #[cfg(not(target_endian = "little"))] 47 | #[inline(always)] 48 | fn from_le(self) -> Self { 49 | $vec::new($word::from_le(self.0), 50 | $word::from_le(self.1), 51 | $word::from_le(self.2), 52 | $word::from_le(self.3)) 53 | } 54 | 55 | #[cfg(target_endian = "little")] 56 | #[inline(always)] 57 | fn to_le(self) -> Self { self } 58 | 59 | #[cfg(not(target_endian = "little"))] 60 | #[inline(always)] 61 | fn to_le(self) -> Self { 62 | $vec::new(self.0.to_le(), 63 | self.1.to_le(), 64 | self.2.to_le(), 65 | self.3.to_le()) 66 | } 67 | 68 | #[inline(always)] 69 | fn wrapping_add(self, rhs: Self) -> Self { self + rhs } 70 | 71 | #[inline(always)] 72 | fn rotate_right_const(self, n: u32) -> Self { 73 | simd_opt::$vec::rotate_right_const(self, n) 74 | } 75 | 76 | #[cfg(feature = "simd")] 77 | #[inline(always)] 78 | fn shuffle_left_1(self) -> Self { 79 | use simdint::simd_shuffle4; 80 | unsafe { simd_shuffle4(self, self, [1, 2, 3, 0]) } 81 | } 82 | 83 | #[cfg(not(feature = "simd"))] 84 | #[inline(always)] 85 | fn shuffle_left_1(self) -> Self { 86 | $vec::new(self.1, self.2, self.3, self.0) 87 | } 88 | 89 | #[cfg(feature = "simd")] 90 | #[inline(always)] 91 | fn shuffle_left_2(self) -> Self { 92 | use simdint::simd_shuffle4; 93 | unsafe { simd_shuffle4(self, self, [2, 3, 0, 1]) } 94 | } 95 | 96 | #[cfg(not(feature = "simd"))] 97 | #[inline(always)] 98 | fn shuffle_left_2(self) -> Self { 99 | $vec::new(self.2, self.3, self.0, self.1) 100 | } 101 | 102 | #[cfg(feature = "simd")] 103 | #[inline(always)] 104 | fn shuffle_left_3(self) -> Self { 105 | use simdint::simd_shuffle4; 106 | unsafe { simd_shuffle4(self, self, [3, 0, 1, 2]) } 107 | } 108 | 109 | #[cfg(not(feature = "simd"))] 110 | #[inline(always)] 111 | fn shuffle_left_3(self) -> Self { 112 | $vec::new(self.3, self.0, self.1, self.2) 113 | } 114 | } 115 | } 116 | } 117 | 118 | impl_vector4!(u32x4, u32); 119 | impl_vector4!(u64x4, u64); 120 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # blake2-rfc 2 | 3 | This is a pure Rust implementation of BLAKE2 based on [RFC 7693]. 4 | 5 | [RFC 7693]: https://tools.ietf.org/html/rfc7693 6 | 7 | ## Design 8 | 9 | This crate follow the common API design for streaming hash functions, 10 | which has one state/context struct and three associated functions: one 11 | to initialize the struct, one which is called repeatedly to process the 12 | incoming data, and one to do the final processing and return the hash. 13 | For the case where the full data is already in memory, there is a 14 | convenience function which does these three steps in a single call. 15 | 16 | This basic design was slightly adapted to make a better use of Rust's 17 | characteristics: the finalization function consumes the struct, doing a 18 | move instead of a borrow, so the struct cannot be accidentally used 19 | after its internal state has been overwritten by the finalization. 20 | 21 | To prevent timing attacks, it's important that the comparison of hash 22 | values takes constant time. To make it easier to do the right thing, the 23 | finalization function returns the result wrapped in a struct which does 24 | a constant-time comparison by default. If a constant-time comparison is 25 | not necessary, the hash result can easily be extracted from this struct. 26 | 27 | ## Limitations 28 | 29 | A single BLAKE2b hash is limited to 16 exabytes, lower than its 30 | theorical limit (but identical to the BLAKE2s theorical limit), due to 31 | the use of a `u64` as the byte counter. This limit can be increased, if 32 | necessary, after either the `extprim` crate (with its `u128` type) or 33 | the `OverflowingOps` trait become usable with the "stable" Rust release. 34 | 35 | This crate does not attempt to clear potentially sensitive data from its 36 | work memory (which includes the state context, the stack, and processor 37 | registers). To do so correctly without a heavy performance penalty would 38 | require help from the compiler. It's better to not attempt to do so than 39 | to present a false assurance. 40 | 41 | ## Non-RFC uses 42 | 43 | This crate is limited to the features described in the RFC: only the 44 | "digest length" and "key length" parameters can be used. 45 | 46 | If you need to use other advanced BLAKE2 features, this crate has an 47 | undocumented function to create a hashing context with an arbitrary 48 | parameter block, and an undocumented function to finalize the last node 49 | in tree hashing mode. You are responsible for creating a valid parameter 50 | block, for hashing the padded key block if using keyed hashing, and for 51 | calling the correct finalization function. The parameter block is not 52 | validated by these functions. 53 | 54 | ## SIMD optimization 55 | 56 | This crate has experimental support for explicit SIMD optimizations. It 57 | requires nightly Rust due to the use of unstable features. 58 | 59 | The following cargo features enable the explicit SIMD optimization: 60 | 61 | * `simd` enables the explicit use of SIMD vectors instead of a plain 62 | struct 63 | * `simd_opt` additionally enables the use of SIMD shuffles to implement 64 | some of the rotates 65 | * `simd_asm` additionally enables the use of inline asm to implement 66 | some of the SIMD shuffles 67 | 68 | While one might expect that each of these is faster than the previous 69 | one, and that they are all faster than not enabling explicit SIMD 70 | vectors, that's not always the case. It can vary depending on target 71 | architecture and compiler options. If you need the extra speed from 72 | these optimizations, benchmark each one (the `bench` feature enables 73 | `cargo bench` in this crate, so you can use for instance `cargo bench 74 | --features="bench simd_asm"`). They have currently been tuned for SSE2 75 | (x86 and x86-64) and NEON (arm). 76 | 77 | ## `no_std` support 78 | 79 | This crate links against the Rust standard library by default, to 80 | provide implementations of `std::io::Write`. To build `no_std`, use 81 | [`default-features = false`](http://doc.crates.io/manifest.html#rules). 82 | 83 | ## License 84 | 85 | Licensed under either of 86 | 87 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 88 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 89 | 90 | at your option. 91 | 92 | ### Contribution 93 | 94 | Unless you explicitly state otherwise, any contribution intentionally 95 | submitted for inclusion in the work by you, as defined in the Apache-2.0 96 | license, shall be dual licensed as above, without any additional terms or 97 | conditions. 98 | -------------------------------------------------------------------------------- /src/blake2b.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 blake2-rfc Developers 2 | // Copyright 2017 Google Inc. 3 | // 4 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 7 | // copied, modified, or distributed except according to those terms. 8 | 9 | //! The BLAKE2b hash function. 10 | //! 11 | //! # Examples 12 | //! 13 | //! ``` 14 | //! use blake2_rfc::blake2b::{Blake2b, blake2b}; 15 | //! 16 | //! // Using the convenience function. 17 | //! let hash = blake2b(64, &[], b"The quick brown fox jumps over the lazy dog"); 18 | //! 19 | //! // Using the state context. 20 | //! let mut context = Blake2b::new(64); 21 | //! context.update(b"The quick brown fox jumps over the lazy dog"); 22 | //! let hash = context.finalize(); 23 | //! 24 | //! // Using the convenience function, with a key. 25 | //! let hash = blake2b(64, b"key", b"The quick brown fox jumps over the lazy dog"); 26 | //! 27 | //! // Using the state context, with a key. 28 | //! let mut context = Blake2b::with_key(64, b"key"); 29 | //! context.update(b"The quick brown fox jumps over the lazy dog"); 30 | //! let hash = context.finalize(); 31 | //! ``` 32 | //! 33 | //! The returned hash is a `Blake2bResult`, which can be compared with 34 | //! a byte string (the comparison will take constant time), or converted 35 | //! into a byte string. 36 | 37 | #![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))] 38 | 39 | blake2_impl!(Blake2b, Blake2bResult, blake2b, u64, u64x4, 64, 32, 24, 16, 63, [ 40 | 0x6A09E667F3BCC908, 0xBB67AE8584CAA73B, 41 | 0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1, 42 | 0x510E527FADE682D1, 0x9B05688C2B3E6C1F, 43 | 0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179, 44 | ]); 45 | 46 | blake2_selftest_impl!(Blake2b, blake2b, [ 47 | 0xC2, 0x3A, 0x78, 0x00, 0xD9, 0x81, 0x23, 0xBD, 48 | 0x10, 0xF5, 0x06, 0xC6, 0x1E, 0x29, 0xDA, 0x56, 49 | 0x03, 0xD7, 0x63, 0xB8, 0xBB, 0xAD, 0x2E, 0x73, 50 | 0x7F, 0x5E, 0x76, 0x5A, 0x7B, 0xCC, 0xD4, 0x75, 51 | ], [ 20, 32, 48, 64 ], [ 0, 3, 128, 129, 255, 1024 ]); 52 | 53 | #[cfg(test)] 54 | mod tests { 55 | #![cfg_attr(feature = "cargo-clippy", allow(result_unwrap_used))] 56 | 57 | extern crate data_encoding; 58 | use self::data_encoding::HEXUPPER; 59 | 60 | use blake2::selftest_seq; 61 | use super::{Blake2b, blake2b}; 62 | 63 | #[test] 64 | fn test_empty() { 65 | assert_eq!(&blake2b(64, &[], b""), &HEXUPPER.decode( 66 | b"786A02F742015903C6C6FD852552D272912F4740E15847618A86E217F71F5419D25E1031AFEE585313896444934EB04B903A685B1448B755D56F701AFE9BE2CE") 67 | .unwrap()[..]); 68 | } 69 | 70 | #[test] 71 | fn test_default() { 72 | assert_eq!(&Blake2b::default().finalize(), &HEXUPPER.decode( 73 | b"786A02F742015903C6C6FD852552D272912F4740E15847618A86E217F71F5419D25E1031AFEE585313896444934EB04B903A685B1448B755D56F701AFE9BE2CE") 74 | .unwrap()[..]); 75 | } 76 | 77 | #[test] 78 | fn selftest() { 79 | super::selftest(); 80 | } 81 | 82 | #[test] 83 | fn test_split() { 84 | let data = selftest_seq(512); 85 | 86 | let mut ctx = Blake2b::new(64); 87 | ctx.update(&data[..32]); 88 | ctx.update(&data[32..64]); 89 | ctx.update(&data[64..448]); 90 | ctx.update(&data[448..]); 91 | 92 | assert_eq!(&ctx.finalize(), &blake2b(64, &[], &data)); 93 | } 94 | 95 | #[cfg(feature = "std")] 96 | #[test] 97 | fn test_write() { 98 | use std::io::prelude::*; 99 | 100 | let data = selftest_seq(1024); 101 | 102 | let mut ctx = Blake2b::new(64); 103 | ctx.update(&data[..]); 104 | 105 | let mut writer = Blake2b::new(64); 106 | writer.write_all(&data[..]).unwrap(); 107 | 108 | assert_eq!(&writer.finalize(), &ctx.finalize()); 109 | } 110 | 111 | #[cfg_attr(debug_assertions, ignore)] 112 | #[test] 113 | fn test_4g() { 114 | const ZEROS: [u8; 4096] = [0; 4096]; 115 | 116 | let mut state = Blake2b::new(64); 117 | for _ in 0..1048576 { 118 | state.update(&ZEROS); 119 | } 120 | assert_eq!(&state.finalize(), &HEXUPPER.decode( 121 | b"645572CA5756F9104329ED543735FC11904F0C18C4DF8ADF930F22D07F3094919A519FF34FD240AE3F5D5B4C8042225C109FB951036FDC99E7D2CD0C1D36B267") 122 | .unwrap()[..]); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/simd_opt/u64x4.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 blake2-rfc Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | 8 | #![cfg_attr(feature = "cargo-clippy", allow(inline_always))] 9 | 10 | use simdty::u64x4; 11 | 12 | #[cfg(feature = "simd_opt")] 13 | #[inline(always)] 14 | pub fn rotate_right_const(vec: u64x4, n: u32) -> u64x4 { 15 | match n { 16 | 32 => rotate_right_32(vec), 17 | 24 => rotate_right_24(vec), 18 | 16 => rotate_right_16(vec), 19 | _ => rotate_right_any(vec, n), 20 | } 21 | } 22 | 23 | #[cfg(not(feature = "simd_opt"))] 24 | #[inline(always)] 25 | pub fn rotate_right_const(vec: u64x4, n: u32) -> u64x4 { 26 | rotate_right_any(vec, n) 27 | } 28 | 29 | #[inline(always)] 30 | fn rotate_right_any(vec: u64x4, n: u32) -> u64x4 { 31 | let r = n as u64; 32 | let l = 64 - r; 33 | 34 | (vec >> u64x4::new(r, r, r, r)) ^ (vec << u64x4::new(l, l, l, l)) 35 | } 36 | 37 | #[cfg(feature = "simd_opt")] 38 | #[inline(always)] 39 | fn rotate_right_32(vec: u64x4) -> u64x4 { 40 | if cfg!(any(target_feature = "sse2", target_feature = "neon")) { 41 | // 2 x pshufd (SSE2) / vpshufd (AVX2) / 2 x vrev (NEON) 42 | transmute_shuffle!(u32x8, simd_shuffle8, vec, 43 | [1, 0, 44 | 3, 2, 45 | 5, 4, 46 | 7, 6]) 47 | } else { 48 | rotate_right_any(vec, 32) 49 | } 50 | } 51 | 52 | #[cfg(feature = "simd_opt")] 53 | #[inline(always)] 54 | fn rotate_right_24(vec: u64x4) -> u64x4 { 55 | if cfg!(all(feature = "simd_asm", 56 | target_feature = "neon", 57 | target_arch = "arm")) { 58 | // 4 x vext (NEON) 59 | rotate_right_vext(vec, 3) 60 | } else if cfg!(target_feature = "ssse3") { 61 | // 2 x pshufb (SSSE3) / vpshufb (AVX2) 62 | transmute_shuffle!(u8x32, simd_shuffle32, vec, 63 | [ 3, 4, 5, 6, 7, 0, 1, 2, 64 | 11, 12, 13, 14, 15, 8, 9, 10, 65 | 19, 20, 21, 22, 23, 16, 17, 18, 66 | 27, 28, 29, 30, 31, 24, 25, 26]) 67 | } else { 68 | rotate_right_any(vec, 24) 69 | } 70 | } 71 | 72 | #[cfg(feature = "simd_opt")] 73 | #[inline(always)] 74 | fn rotate_right_16(vec: u64x4) -> u64x4 { 75 | if cfg!(all(feature = "simd_asm", 76 | target_feature = "neon", 77 | target_arch = "arm")) { 78 | // 4 x vext (NEON) 79 | rotate_right_vext(vec, 2) 80 | } else if cfg!(target_feature = "ssse3") { 81 | // 2 x pshufb (SSSE3) / vpshufb (AVX2) 82 | transmute_shuffle!(u8x32, simd_shuffle32, vec, 83 | [ 2, 3, 4, 5, 6, 7, 0, 1, 84 | 10, 11, 12, 13, 14, 15, 8, 9, 85 | 18, 19, 20, 21, 22, 23, 16, 17, 86 | 26, 27, 28, 29, 30, 31, 24, 25]) 87 | } else if cfg!(target_feature = "sse2") { 88 | // 2 x pshuflw+pshufhw (SSE2) 89 | transmute_shuffle!(u16x16, simd_shuffle16, vec, 90 | [ 1, 2, 3, 0, 91 | 5, 6, 7, 4, 92 | 9, 10, 11, 8, 93 | 13, 14, 15, 12]) 94 | } else { 95 | rotate_right_any(vec, 16) 96 | } 97 | } 98 | 99 | #[cfg(all(feature = "simd_asm", 100 | target_feature = "neon", 101 | target_arch = "arm"))] 102 | mod simd_asm_neon_arm { 103 | use simdty::{u64x2, u64x4}; 104 | 105 | #[inline(always)] 106 | fn vext_u64(vec: u64x2, b: u8) -> u64x2 { 107 | unsafe { 108 | let result: u64x2; 109 | asm!("vext.8 ${0:e}, ${1:e}, ${1:e}, $2\nvext.8 ${0:f}, ${1:f}, ${1:f}, $2" 110 | : "=w" (result) 111 | : "w" (vec), "n" (b)); 112 | result 113 | } 114 | } 115 | 116 | #[inline(always)] 117 | pub fn rotate_right_vext(vec: u64x4, b: u8) -> u64x4 { 118 | use simdint::{simd_shuffle2, simd_shuffle4}; 119 | 120 | unsafe { 121 | let tmp0 = vext_u64(simd_shuffle2(vec, vec, [0, 1]), b); 122 | let tmp1 = vext_u64(simd_shuffle2(vec, vec, [2, 3]), b); 123 | simd_shuffle4(tmp0, tmp1, [0, 1, 2, 3]) 124 | } 125 | } 126 | } 127 | 128 | #[cfg(all(feature = "simd_asm", 129 | target_feature = "neon", 130 | target_arch = "arm"))] 131 | use self::simd_asm_neon_arm::rotate_right_vext; 132 | 133 | #[cfg(feature = "simd_opt")] 134 | #[cfg(not(all(feature = "simd_asm", 135 | target_feature = "neon", 136 | target_arch = "arm")))] 137 | fn rotate_right_vext(_vec: u64x4, _n: u8) -> u64x4 { unreachable!() } 138 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /src/blake2.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2015 blake2-rfc Developers 2 | // 3 | // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | // copied, modified, or distributed except according to those terms. 7 | 8 | use arrayvec::ArrayVec; 9 | 10 | pub const SIGMA: [[usize; 16]; 10] = [ 11 | [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], 12 | [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3], 13 | [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4], 14 | [ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8], 15 | [ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13], 16 | [ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9], 17 | [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11], 18 | [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10], 19 | [ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5], 20 | [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0], 21 | ]; 22 | 23 | macro_rules! blake2_impl { 24 | ($state:ident, $result:ident, $func:ident, $word:ident, $vec:ident, 25 | $bytes:expr, $R1:expr, $R2:expr, $R3:expr, $R4:expr, $IV:expr) => { 26 | use core::cmp; 27 | 28 | #[cfg(feature = "std")] 29 | use std::io; 30 | 31 | use $crate::as_bytes::AsBytes; 32 | use $crate::bytes::BytesExt; 33 | use $crate::constant_time_eq::constant_time_eq; 34 | use $crate::simd::{Vector4, $vec}; 35 | 36 | /// Container for a hash result. 37 | /// 38 | /// This container uses a constant-time comparison for equality. 39 | /// If a constant-time comparison is not necessary, the hash 40 | /// result can be extracted with the `as_bytes` method. 41 | #[derive(Clone, Copy, Debug)] 42 | pub struct $result { 43 | h: [$vec; 2], 44 | nn: usize, 45 | } 46 | 47 | #[cfg_attr(feature = "cargo-clippy", allow(len_without_is_empty))] 48 | impl $result { 49 | /// Returns the contained hash result as a byte string. 50 | #[inline] 51 | pub fn as_bytes(&self) -> &[u8] { &self.h.as_bytes()[..self.nn] } 52 | 53 | /// Returns the length of the hash result. 54 | /// 55 | /// This is the same value that was used to create the hash 56 | /// context. 57 | #[inline] 58 | pub fn len(&self) -> usize { self.nn } 59 | } 60 | 61 | impl AsRef<[u8]> for $result { 62 | #[inline] 63 | fn as_ref(&self) -> &[u8] { self.as_bytes() } 64 | } 65 | 66 | impl Eq for $result { } 67 | 68 | impl PartialEq for $result { 69 | #[inline] 70 | fn eq(&self, other: &Self) -> bool { 71 | constant_time_eq(self.as_bytes(), other.as_bytes()) 72 | } 73 | } 74 | 75 | impl PartialEq<[u8]> for $result { 76 | #[inline] 77 | fn eq(&self, other: &[u8]) -> bool { 78 | constant_time_eq(self.as_bytes(), other) 79 | } 80 | } 81 | 82 | /// State context. 83 | #[derive(Clone, Debug)] 84 | pub struct $state { 85 | m: [$word; 16], 86 | h: [$vec; 2], 87 | t: u64, 88 | nn: usize, 89 | } 90 | 91 | const IV: [$word; 8] = $IV; 92 | 93 | #[inline(always)] 94 | fn iv0() -> $vec { $vec::new(IV[0], IV[1], IV[2], IV[3]) } 95 | #[inline(always)] 96 | fn iv1() -> $vec { $vec::new(IV[4], IV[5], IV[6], IV[7]) } 97 | 98 | /// Convenience function for all-in-one computation. 99 | pub fn $func(nn: usize, k: &[u8], data: &[u8]) -> $result { 100 | let mut state = $state::with_key(nn, k); 101 | state.update(data); 102 | state.finalize() 103 | } 104 | 105 | impl $state { 106 | /// Creates a new hashing context without a key. 107 | pub fn new(nn: usize) -> Self { Self::with_key(nn, &[]) } 108 | 109 | /// Creates a new hashing context with a key. 110 | #[cfg_attr(feature = "cargo-clippy", allow(cast_possible_truncation))] 111 | pub fn with_key(nn: usize, k: &[u8]) -> Self { 112 | let kk = k.len(); 113 | assert!(nn >= 1 && nn <= $bytes && kk <= $bytes); 114 | 115 | let p0 = 0x01010000 ^ ((kk as $word) << 8) ^ (nn as $word); 116 | let mut state = $state { 117 | m: [0; 16], 118 | h: [iv0() ^ $vec::new(p0, 0, 0, 0), iv1()], 119 | t: 0, 120 | nn: nn, 121 | }; 122 | 123 | if kk > 0 { 124 | state.m.as_mut_bytes().copy_bytes_from(k); 125 | state.t = $bytes * 2; 126 | } 127 | state 128 | } 129 | 130 | #[doc(hidden)] 131 | #[cfg_attr(feature = "cargo-clippy", allow(cast_possible_truncation))] 132 | pub fn with_parameter_block(p: &[$word; 8]) -> Self { 133 | let nn = p[0] as u8 as usize; 134 | let kk = (p[0] >> 8) as u8 as usize; 135 | assert!(nn >= 1 && nn <= $bytes && kk <= $bytes); 136 | 137 | $state { 138 | m: [0; 16], 139 | h: [iv0() ^ $vec::new(p[0], p[1], p[2], p[3]), 140 | iv1() ^ $vec::new(p[4], p[5], p[6], p[7])], 141 | t: 0, 142 | nn: nn, 143 | } 144 | } 145 | 146 | /// Updates the hashing context with more data. 147 | #[cfg_attr(feature = "cargo-clippy", allow(cast_possible_truncation))] 148 | pub fn update(&mut self, data: &[u8]) { 149 | let mut rest = data; 150 | 151 | let off = (self.t % ($bytes * 2)) as usize; 152 | if off != 0 || self.t == 0 { 153 | let len = cmp::min(($bytes * 2) - off, rest.len()); 154 | 155 | let part = &rest[..len]; 156 | rest = &rest[part.len()..]; 157 | 158 | self.m.as_mut_bytes()[off..].copy_bytes_from(part); 159 | self.t = self.t.checked_add(part.len() as u64) 160 | .expect("hash data length overflow"); 161 | } 162 | 163 | while rest.len() >= $bytes * 2 { 164 | self.compress(0, 0); 165 | 166 | let part = &rest[..($bytes * 2)]; 167 | rest = &rest[part.len()..]; 168 | 169 | self.m.as_mut_bytes().copy_bytes_from(part); 170 | self.t = self.t.checked_add(part.len() as u64) 171 | .expect("hash data length overflow"); 172 | } 173 | 174 | if rest.len() > 0 { 175 | self.compress(0, 0); 176 | 177 | self.m.as_mut_bytes().copy_bytes_from(rest); 178 | self.t = self.t.checked_add(rest.len() as u64) 179 | .expect("hash data length overflow"); 180 | } 181 | } 182 | 183 | #[cfg_attr(feature = "cargo-clippy", allow(cast_possible_truncation))] 184 | fn finalize_with_flag(&mut self, f1: $word) { 185 | let off = (self.t % ($bytes * 2)) as usize; 186 | if off != 0 { 187 | self.m.as_mut_bytes()[off..].set_bytes(0); 188 | } 189 | 190 | self.compress(!0, f1); 191 | } 192 | 193 | /// Consumes the hashing context and returns the resulting hash. 194 | #[inline] 195 | pub fn finalize(mut self) -> $result { 196 | self.finalize_with_flag(0); 197 | self.into_result() 198 | } 199 | 200 | #[doc(hidden)] 201 | #[inline] 202 | pub fn finalize_last_node(mut self) -> $result { 203 | self.finalize_with_flag(!0); 204 | self.into_result() 205 | } 206 | 207 | #[doc(hidden)] 208 | pub fn finalize_inplace(&mut self) -> &[u8] { 209 | self.finalize_with_flag(0); 210 | self.result_inplace() 211 | } 212 | 213 | #[doc(hidden)] 214 | pub fn finalize_last_node_inplace(&mut self) -> &[u8] { 215 | self.finalize_with_flag(!0); 216 | self.result_inplace() 217 | } 218 | 219 | #[inline] 220 | fn into_result(self) -> $result { 221 | $result { 222 | h: [self.h[0].to_le(), self.h[1].to_le()], 223 | nn: self.nn, 224 | } 225 | } 226 | 227 | fn result_inplace(&mut self) -> &[u8] { 228 | self.h[0] = self.h[0].to_le(); 229 | self.h[1] = self.h[1].to_le(); 230 | 231 | let result = &self.h.as_bytes()[..self.nn]; 232 | self.nn = 0; // poison self 233 | result 234 | } 235 | 236 | #[inline(always)] 237 | fn quarter_round(v: &mut [$vec; 4], rd: u32, rb: u32, m: $vec) { 238 | v[0] = v[0].wrapping_add(v[1]).wrapping_add(m.from_le()); 239 | v[3] = (v[3] ^ v[0]).rotate_right_const(rd); 240 | v[2] = v[2].wrapping_add(v[3]); 241 | v[1] = (v[1] ^ v[2]).rotate_right_const(rb); 242 | } 243 | 244 | #[inline(always)] 245 | fn shuffle(v: &mut [$vec; 4]) { 246 | v[1] = v[1].shuffle_left_1(); 247 | v[2] = v[2].shuffle_left_2(); 248 | v[3] = v[3].shuffle_left_3(); 249 | } 250 | 251 | #[inline(always)] 252 | fn unshuffle(v: &mut [$vec; 4]) { 253 | v[1] = v[1].shuffle_right_1(); 254 | v[2] = v[2].shuffle_right_2(); 255 | v[3] = v[3].shuffle_right_3(); 256 | } 257 | 258 | #[inline(always)] 259 | fn round(v: &mut [$vec; 4], m: &[$word; 16], s: &[usize; 16]) { 260 | $state::quarter_round(v, $R1, $R2, $vec::gather(m, 261 | s[ 0], s[ 2], s[ 4], s[ 6])); 262 | $state::quarter_round(v, $R3, $R4, $vec::gather(m, 263 | s[ 1], s[ 3], s[ 5], s[ 7])); 264 | 265 | $state::shuffle(v); 266 | $state::quarter_round(v, $R1, $R2, $vec::gather(m, 267 | s[ 8], s[10], s[12], s[14])); 268 | $state::quarter_round(v, $R3, $R4, $vec::gather(m, 269 | s[ 9], s[11], s[13], s[15])); 270 | $state::unshuffle(v); 271 | } 272 | 273 | #[cfg_attr(feature = "cargo-clippy", allow(cast_possible_truncation, eq_op))] 274 | fn compress(&mut self, f0: $word, f1: $word) { 275 | use $crate::blake2::SIGMA; 276 | 277 | let m = &self.m; 278 | let h = &mut self.h; 279 | 280 | let t0 = self.t as $word; 281 | let t1 = match $bytes { 282 | 64 => 0, 283 | 32 => (self.t >> 32) as $word, 284 | _ => unreachable!(), 285 | }; 286 | 287 | let mut v = [ 288 | h[0], 289 | h[1], 290 | iv0(), 291 | iv1() ^ $vec::new(t0, t1, f0, f1), 292 | ]; 293 | 294 | $state::round(&mut v, m, &SIGMA[0]); 295 | $state::round(&mut v, m, &SIGMA[1]); 296 | $state::round(&mut v, m, &SIGMA[2]); 297 | $state::round(&mut v, m, &SIGMA[3]); 298 | $state::round(&mut v, m, &SIGMA[4]); 299 | $state::round(&mut v, m, &SIGMA[5]); 300 | $state::round(&mut v, m, &SIGMA[6]); 301 | $state::round(&mut v, m, &SIGMA[7]); 302 | $state::round(&mut v, m, &SIGMA[8]); 303 | $state::round(&mut v, m, &SIGMA[9]); 304 | if $bytes > 32 { 305 | $state::round(&mut v, m, &SIGMA[0]); 306 | $state::round(&mut v, m, &SIGMA[1]); 307 | } 308 | 309 | h[0] = h[0] ^ (v[0] ^ v[2]); 310 | h[1] = h[1] ^ (v[1] ^ v[3]); 311 | } 312 | } 313 | 314 | impl Default for $state { 315 | fn default() -> Self { 316 | Self::new($bytes) 317 | } 318 | } 319 | 320 | #[cfg(feature = "std")] 321 | impl io::Write for $state { 322 | fn write(&mut self, buf: &[u8]) -> io::Result { 323 | if self.t.checked_add(buf.len() as u64).is_none() { 324 | return Err(io::Error::new(io::ErrorKind::WriteZero, 325 | "counter overflow")); 326 | } 327 | 328 | self.update(buf); 329 | Ok(buf.len()) 330 | } 331 | 332 | #[inline] 333 | fn flush(&mut self) -> io::Result<()> { 334 | Ok(()) 335 | } 336 | } 337 | } 338 | } 339 | 340 | #[cfg_attr(feature = "cargo-clippy", allow(cast_possible_truncation, unreadable_literal))] 341 | #[cold] 342 | #[doc(hidden)] 343 | pub fn selftest_seq(len: usize) -> ArrayVec<[u8; 1024]> { 344 | use core::num::Wrapping; 345 | 346 | let seed = Wrapping(len as u32); 347 | let mut out = ArrayVec::new(); 348 | 349 | let mut a = Wrapping(0xDEAD4BAD) * seed; 350 | let mut b = Wrapping(1); 351 | 352 | for _ in 0..len { 353 | let t = a + b; 354 | a = b; 355 | b = t; 356 | out.push((t >> 24).0 as u8); 357 | } 358 | out 359 | } 360 | 361 | macro_rules! blake2_selftest_impl { 362 | ($state:ident, $func:ident, $res:expr, $md_len:expr, $in_len:expr) => { 363 | /// Runs the self-test for this hash function. 364 | #[cold] 365 | pub fn selftest() { 366 | use $crate::blake2::selftest_seq; 367 | 368 | const BLAKE2_RES: [u8; 32] = $res; 369 | const B2_MD_LEN: [usize; 4] = $md_len; 370 | const B2_IN_LEN: [usize; 6] = $in_len; 371 | 372 | let mut state = $state::new(32); 373 | 374 | for &outlen in &B2_MD_LEN { 375 | for &inlen in &B2_IN_LEN { 376 | let data = selftest_seq(inlen); 377 | let md = $func(outlen, &[], &data); 378 | state.update(md.as_bytes()); 379 | 380 | let key = selftest_seq(outlen); 381 | let md = $func(outlen, &key, &data); 382 | state.update(md.as_bytes()); 383 | } 384 | } 385 | 386 | assert_eq!(&state.finalize(), &BLAKE2_RES[..]); 387 | } 388 | } 389 | } 390 | --------------------------------------------------------------------------------