1use crate::blake2b_ref::{
2 blake2b_final, blake2b_init_key_with_param, blake2b_init_param, blake2b_param, blake2b_state,
3 blake2b_update, size_t, BLAKE2B_KEYBYTES, BLAKE2B_OUTBYTES, BLAKE2B_PERSONALBYTES,
4 BLAKE2B_SALTBYTES,
5};
6use crate::libc::*;
7
8pub struct Blake2b {
9 pub(crate) state: blake2b_state,
10}
11
12pub struct Blake2bBuilder {
13 pub(crate) state: blake2b_state,
14 pub(crate) param: blake2b_param,
15 pub(crate) key_len: usize,
16 pub(crate) key: [u8; BLAKE2B_KEYBYTES as usize],
17}
18
19impl Blake2bBuilder {
20 pub fn new(out_len: usize) -> Self {
21 assert!(out_len >= 1 && out_len <= BLAKE2B_OUTBYTES as usize);
22 let param = blake2b_param {
23 digest_length: out_len as u8,
24 key_length: 0,
25 fanout: 1,
26 depth: 1,
27 leaf_length: 0,
28 node_offset: 0,
29 xof_length: 0,
30 node_depth: 0,
31 inner_length: 0,
32 reserved: [0u8; 14usize],
33 salt: [0u8; BLAKE2B_SALTBYTES as usize],
34 personal: [0u8; BLAKE2B_PERSONALBYTES as usize],
35 };
36 let state = unsafe { ::core::mem::MaybeUninit::zeroed().assume_init() }; let key_len = 0;
38 let key = [0u8; BLAKE2B_KEYBYTES as usize];
39
40 Blake2bBuilder {
41 param,
42 state,
43 key_len,
44 key,
45 }
46 }
47
48 pub fn salt(mut self, salt: &[u8]) -> Blake2bBuilder {
49 let len = salt.len();
50 assert!(len <= BLAKE2B_SALTBYTES as usize);
51
52 unsafe {
53 ::core::ptr::copy_nonoverlapping(salt.as_ptr(), self.param.salt.as_mut_ptr(), len);
54 }
55 self
56 }
57
58 pub fn personal(mut self, personal: &[u8]) -> Blake2bBuilder {
59 let len = personal.len();
60 assert!(len <= BLAKE2B_PERSONALBYTES as usize);
61
62 unsafe {
63 ::core::ptr::copy_nonoverlapping(
64 personal.as_ptr(),
65 self.param.personal.as_mut_ptr(),
66 len,
67 );
68 }
69 self
70 }
71
72 pub fn key(mut self, key: &[u8]) -> Blake2bBuilder {
73 let key_len = key.len();
74 assert!(key_len <= BLAKE2B_KEYBYTES as usize);
75 self.param.key_length = key_len as u8;
76 self.key_len = key_len;
77
78 unsafe {
79 ::core::ptr::copy_nonoverlapping(key.as_ptr(), self.key.as_mut_ptr(), key_len);
80 }
81 self
82 }
83
84 pub fn build(self) -> Blake2b {
85 let Blake2bBuilder {
86 mut state,
87 param,
88 key,
89 key_len,
90 } = self;
91 if self.key_len == 0 {
92 unsafe {
93 blake2b_init_param(
94 &mut state as *mut blake2b_state,
95 ¶m as *const blake2b_param,
96 );
97 }
98 } else {
99 unsafe {
100 blake2b_init_key_with_param(
101 &mut state as *mut blake2b_state,
102 ¶m as *const blake2b_param,
103 key.as_ptr() as *const c_void,
104 key_len as size_t,
105 );
106 }
107 }
108 Blake2b { state }
109 }
110}
111
112impl Blake2b {
113 pub fn update(&mut self, data: &[u8]) {
114 unsafe {
115 blake2b_update(
116 &mut self.state as *mut blake2b_state,
117 data.as_ptr() as *const c_void,
118 data.len() as size_t,
119 );
120 }
121 }
122
123 pub fn finalize(mut self, dst: &mut [u8]) {
124 unsafe {
125 blake2b_final(
126 &mut self.state as *mut blake2b_state,
127 dst.as_mut_ptr() as *mut c_void,
128 dst.len() as size_t,
129 );
130 }
131 }
132}
133
134pub fn blake2b(key: &[u8], data: &[u8], dst: &mut [u8]) {
135 let mut blake2b = Blake2bBuilder::new(dst.len()).key(key).build();
136 blake2b.update(data);
137 blake2b.finalize(dst)
138}
139
140#[cfg(test)]
141mod tests {
142 use super::Blake2bBuilder;
143 use faster_hex::{hex_decode, hex_string};
144 use serde_derive::Deserialize;
145 use std::fs::File;
146 use std::io::BufReader;
147 use std::path::Path;
148
149 #[derive(Deserialize, Debug)]
150 struct TestItem {
151 outlen: usize,
152 out: String,
153 input: String,
154 key: String,
155 salt: String,
156 personal: String,
157 }
158
159 #[test]
160 fn test_full() {
161 let test_path = Path::new(env!("CARGO_MANIFEST_DIR")).join("fixtures/test.json");
162
163 let f = File::open(test_path).unwrap();
164 let reader = BufReader::new(f);
165 let tests: Vec<TestItem> = serde_json::from_reader(reader).unwrap();
166
167 for test in tests {
168 let mut hash = vec![0u8; test.outlen];
169 let mut blake2b = Blake2bBuilder::new(test.outlen)
170 .key(&unhex(test.key.as_bytes()))
171 .personal(&unhex(test.personal.as_bytes()))
172 .salt(&unhex(test.salt.as_bytes()))
173 .build();
174 blake2b.update(&unhex(test.input.as_bytes()));
175 blake2b.finalize(&mut hash);
176 assert_eq!(hex_string(&hash).unwrap(), test.out);
177 }
178 }
179
180 fn unhex(src: &[u8]) -> Vec<u8> {
181 let len = src.len() / 2;
182 let mut ret = vec![0u8; len];
183 if !src.is_empty() {
184 hex_decode(src, &mut ret).unwrap();
185 }
186 ret
187 }
188}