yasmf_hash/
lib.rs

1//! yasmf-hash
2//!
3//! Encode and decode [yasmf-hashes](https://github.com/AljoschaMeyer/yamf-hash)
4//!
5#![cfg_attr(not(feature = "std"), no_std)]
6
7#[macro_use]
8extern crate serde_derive;
9#[macro_use]
10extern crate static_assertions;
11
12use crate::error::*;
13#[cfg(feature = "std")]
14mod util;
15pub mod error;
16
17#[cfg(feature = "std")]
18use crate::util::hex_serde::{hex_from_bytes, vec_from_hex};
19use arrayvec::ArrayVec;
20pub use blake3::{hash as blake3, Hash as Blake3Hash, OUT_LEN as BLAKE3_OUT_LEN};
21use core::borrow::Borrow;
22use core::iter::FromIterator;
23
24#[cfg(feature = "std")]
25use std::io::Write;
26
27use varu64::{decode as varu64_decode, encode as varu64_encode, encoding_length};
28
29pub const BLAKE3_HASH_SIZE: usize = 32;
30// This is a way to hard code a value that cbindgen can use, but make sure at compile time
31// that the value is actually correct.
32const_assert_eq!(blake3_hash_size; BLAKE3_HASH_SIZE, BLAKE3_OUT_LEN);
33
34pub const BLAKE3_NUMERIC_ID: u64 = 0;
35
36/// The maximum number of bytes this will use for any variant.
37///
38/// This is a bit yuck because it knows the number of bytes varu64 uses to encode the
39/// Blake3 hash size and the blake3 numeric id (2).
40/// This is unlikely to cause a problem until there are hundreds of variants.
41pub const MAX_YAMF_HASH_SIZE: usize = BLAKE3_HASH_SIZE + 2;
42
43/// Variants of `YasmfHash`
44#[derive(Deserialize, Serialize, Debug, Eq, Clone)]
45pub enum YasmfHash<T: Borrow<[u8]> + Clone> {
46    #[cfg_attr(
47        feature = "std",
48        serde(serialize_with = "hex_from_bytes", deserialize_with = "vec_from_hex")
49    )]
50    #[cfg_attr(feature = "std", serde(bound(deserialize = "T: From<Vec<u8>>")))]
51    Blake3(T),
52}
53
54impl<B1: Borrow<[u8]> + Clone, B2: Borrow<[u8]> + Clone> PartialEq<YasmfHash<B1>> for YasmfHash<B2> {
55    fn eq(&self, other: &YasmfHash<B1>) -> bool {
56        match (self, other) {
57            (YasmfHash::Blake3(vec), YasmfHash::Blake3(vec2)) => vec.borrow() == vec2.borrow(),
58        }
59    }
60}
61
62pub fn new_blake3(bytes: &[u8]) -> YasmfHash<ArrayVec<[u8; BLAKE3_HASH_SIZE]>> {
63    let hash_bytes = blake3(bytes);
64
65    let vec_bytes: ArrayVec<[u8; BLAKE3_HASH_SIZE]> =
66        ArrayVec::from_iter(hash_bytes.as_bytes().iter().map(|b| *b));
67
68    YasmfHash::Blake3(vec_bytes)
69}
70
71impl<'a> From<&'a YasmfHash<ArrayVec<[u8; BLAKE3_HASH_SIZE]>>> for YasmfHash<&'a [u8]> {
72    fn from(hash: &YasmfHash<ArrayVec<[u8; BLAKE3_HASH_SIZE]>>) -> YasmfHash<&[u8]> {
73        match hash {
74            YasmfHash::Blake3(bytes) => YasmfHash::Blake3(&bytes[..]),
75        }
76    }
77}
78
79
80impl<'a> From<Blake3Hash> for YasmfHash<ArrayVec<[u8; BLAKE3_HASH_SIZE]>> {
81    fn from(hash: Blake3Hash) -> Self {
82        let vec_bytes: ArrayVec<[u8; BLAKE3_HASH_SIZE]> =
83            ArrayVec::from_iter(hash.as_bytes().iter().map(|b| *b));
84
85        YasmfHash::Blake3(vec_bytes)
86    }
87}
88impl<T: Borrow<[u8]> + Clone> YasmfHash<T> {
89    /// Encode a YasmfHash into the out buffer.
90    pub fn encode(&self, out: &mut [u8]) -> Result<usize, Error> {
91        let encoded_size = self.encoding_length();
92
93        match (self, out.len()) {
94            (YasmfHash::Blake3(vec), len) if len >= encoded_size => {
95                varu64_encode(BLAKE3_NUMERIC_ID, &mut out[0..1]);
96                varu64_encode(BLAKE3_HASH_SIZE as u64, &mut out[1..2]);
97                out[2..encoded_size].copy_from_slice(vec.borrow());
98                Ok(encoded_size)
99            }
100            _ => Err(Error::EncodeError),
101        }
102    }
103
104    pub fn encoding_length(&self) -> usize {
105        match self {
106            YasmfHash::Blake3(_) => {
107                encoding_length(BLAKE3_NUMERIC_ID)
108                    + encoding_length(BLAKE3_HASH_SIZE as u64)
109                    + BLAKE3_HASH_SIZE
110            }
111        }
112    }
113
114    /// Decode the `bytes` as a `YasmfHash`
115    pub fn decode<'a>(bytes: &'a [u8]) -> Result<(YasmfHash<&'a [u8]>, &'a [u8]), Error> {
116        match varu64_decode(&bytes) {
117            Ok((BLAKE3_NUMERIC_ID, remaining_bytes)) if remaining_bytes.len() >= 33 => {
118                let hash = &remaining_bytes[1..33];
119                Ok((YasmfHash::Blake3(hash), &remaining_bytes[33..]))
120            }
121            Err((_, _)) => Err(Error::DecodeVaru64Error),
122            _ => Err(Error::DecodeError {}),
123        }
124    }
125
126    /// Decode the `bytes` as a `YasmfHash`
127    pub fn decode_owned<'a>(
128        bytes: &'a [u8],
129    ) -> Result<(YasmfHash<ArrayVec<[u8; BLAKE3_HASH_SIZE]>>, &'a [u8]), Error> {
130        match varu64_decode(&bytes) {
131            Ok((BLAKE3_NUMERIC_ID, remaining_bytes)) if remaining_bytes.len() >= 33 => {
132                let mut vec = ArrayVec::new();
133                let slice = &remaining_bytes[1..33];
134                vec.try_extend_from_slice(slice).unwrap();
135                Ok((YasmfHash::Blake3(vec), &remaining_bytes[33..]))
136            }
137            Err((_, _)) => Err(Error::DecodeVaru64Error),
138            _ => Err(Error::DecodeError {}),
139        }
140    }
141
142    /// Encode a YasmfHash into the writer.
143    #[cfg(feature = "std")]
144    pub fn encode_write<W: Write>(&self, mut w: W) -> Result<(), Error> {
145        let mut out = [0; 2];
146        match self {
147            YasmfHash::Blake3(vec) => {
148                varu64_encode(BLAKE3_NUMERIC_ID, &mut out[0..1]);
149                varu64_encode(BLAKE3_HASH_SIZE as u64, &mut out[1..2]);
150                w.write_all(&out).map_err(|_| Error::EncodeWriteError)?;
151                w.write_all(vec.borrow())
152                    .map_err(|_| Error::EncodeWriteError)?;
153                Ok(())
154            }
155        }
156    }
157}
158
159#[cfg(test)]
160mod tests {
161    use crate::MAX_YAMF_HASH_SIZE;
162
163    use super::{new_blake3, blake3, Error, YasmfHash, BLAKE3_HASH_SIZE};
164    use arrayvec::ArrayVec;
165    use core::iter::FromIterator;
166
167    #[test]
168    fn encode_yasmf() {
169        let hash_bytes = vec![0xFF; BLAKE3_HASH_SIZE];
170        let yasmf_hash = YasmfHash::Blake3(hash_bytes);
171
172        let mut encoded = vec![0; MAX_YAMF_HASH_SIZE];
173        let length = yasmf_hash.encode(&mut encoded).unwrap();
174        assert_eq!(length, MAX_YAMF_HASH_SIZE);
175        assert_eq!(encoded[0], 0);
176        assert_eq!(encoded[1], 32);
177    }
178    #[test]
179    fn encode_yasmf_write() {
180        let hash_bytes = vec![0xFF; BLAKE3_HASH_SIZE];
181        let yasmf_hash = YasmfHash::Blake3(hash_bytes);
182
183        let mut encoded = Vec::new();
184        yasmf_hash.encode_write(&mut encoded).unwrap();
185        assert_eq!(encoded.len(), 34);
186        assert_eq!(encoded[0], 0);
187        assert_eq!(encoded[1], 32);
188    }
189    #[test]
190    fn encode_yasmf_not_enough_bytes_for_varu() {
191        let hash_bytes = vec![0xFF; 4];
192        let yasmf_hash = YasmfHash::Blake3(hash_bytes);
193
194        let mut encoded = [0; 2];
195        match yasmf_hash.encode_write(&mut encoded[..]) {
196            Err(Error::EncodeWriteError) => {}
197            _ => panic!("Go ok, expected error"),
198        }
199    }
200    #[test]
201    fn encode_yasmf_not_enough_bytes_for_hash() {
202        let hash_bytes = vec![0xFF; 4];
203        let yasmf_hash = YasmfHash::Blake3(hash_bytes);
204
205        let mut encoded = [0; 4];
206        match yasmf_hash.encode_write(&mut encoded[..]) {
207            Err(Error::EncodeWriteError) => {}
208            _ => panic!("Go ok, expected error"),
209        }
210    }
211    #[test]
212    fn decode_yasmf() {
213        let mut hash_bytes = vec![0xFF; 35];
214        hash_bytes[0] = 0;
215        hash_bytes[1] = 32;
216        hash_bytes[34] = 0xAA;
217        let result = YasmfHash::<&[u8]>::decode(&hash_bytes);
218
219        match result {
220            Ok((YasmfHash::Blake3(vec), remaining_bytes)) => {
221                assert_eq!(vec.len(), 32);
222                assert_eq!(vec, &hash_bytes[2..34]);
223                assert_eq!(remaining_bytes, &[0xAA]);
224            }
225            _ => panic!(),
226        }
227    }
228    #[test]
229    fn decode_yasmf_varu_error() {
230        let mut hash_bytes = vec![0xFF; 67];
231        hash_bytes[0] = 248;
232        hash_bytes[1] = 1;
233        hash_bytes[2] = 32;
234        hash_bytes[66] = 0xAA;
235        let result = YasmfHash::<&[u8]>::decode(&hash_bytes);
236
237        match result {
238            Err(Error::DecodeVaru64Error) => {}
239            _ => panic!(),
240        }
241    }
242    #[test]
243    fn decode_yasmf_not_enough_bytes_error() {
244        let mut hash_bytes = vec![0xFF; BLAKE3_HASH_SIZE];
245        hash_bytes[0] = 0;
246        hash_bytes[1] = 32;
247        let result = YasmfHash::<&[u8]>::decode(&hash_bytes);
248
249        match result {
250            Err(Error::DecodeError {}) => {}
251            _ => panic!(),
252        }
253    }
254
255    #[test]
256    fn blake_yasmf_hash() {
257        let lam = || {
258            let hash_bytes = blake3(&[1, 2]);
259            let vec_bytes: ArrayVec<[u8; BLAKE3_HASH_SIZE]> =
260                ArrayVec::from_iter(hash_bytes.as_bytes().iter().map(|b| *b));
261            YasmfHash::Blake3(vec_bytes)
262        };
263        let _ = lam();
264    }
265
266    #[test]
267    fn blake2b_yasmf_hash_eq() {
268        let lam = || {
269            let hash_bytes = blake3(&[1, 2]);
270            let vec_bytes: ArrayVec<[u8; BLAKE3_HASH_SIZE]> =
271                ArrayVec::from_iter(hash_bytes.as_bytes().iter().map(|b| *b));
272            YasmfHash::Blake3(vec_bytes)
273        };
274        let result = lam();
275
276        let hash_bytes = blake3(&[1, 2]);
277        let result2 = YasmfHash::Blake3(&hash_bytes.as_bytes()[..]);
278
279        assert_eq!(result, result2);
280        assert_eq!(result2, result);
281    }
282
283    #[test]
284    fn owned_yasmf_hash() {
285        let lam = || {
286            let mut hash_bytes = ArrayVec::<[u8; BLAKE3_HASH_SIZE]>::new();
287            hash_bytes.push(1);
288            hash_bytes.push(64);
289            YasmfHash::Blake3(hash_bytes)
290        };
291        let _ = lam();
292    }
293    #[test]
294    fn ref_yasmf_hash() {
295        let mut hash_bytes = ArrayVec::<[u8; BLAKE3_HASH_SIZE * 2]>::new();
296        hash_bytes.push(1);
297        hash_bytes.push(64);
298        YasmfHash::Blake3(hash_bytes);
299    }
300    #[test]
301    fn from_owned_to_ref_yasmf_hash() {
302        let lam = || {
303            let mut hash_bytes = ArrayVec::<[u8; BLAKE3_HASH_SIZE]>::new();
304            hash_bytes.push(1);
305            hash_bytes.push(64);
306            YasmfHash::Blake3(hash_bytes)
307        };
308        let result = lam();
309        let _: YasmfHash<&[u8]> = YasmfHash::from(&result);
310    }
311
312    #[test]
313    fn encode_decode_blake2b() {
314        let bytes = vec![1, 2, 3];
315        let yasmf_hash = new_blake3(&bytes);
316
317        let mut encoded = Vec::new();
318        yasmf_hash.encode_write(&mut encoded).unwrap();
319
320        let (decoded, _) = YasmfHash::<ArrayVec<[u8; BLAKE3_HASH_SIZE]>>::decode_owned(&encoded).unwrap();
321
322        assert_eq!(decoded, yasmf_hash);
323    }
324
325    #[test]
326    fn encode_decode_blake3() {
327        let bytes = vec![1, 2, 3];
328        let yasmf_hash = new_blake3(&bytes);
329
330        let mut encoded = Vec::new();
331        yasmf_hash.encode_write(&mut encoded).unwrap();
332
333        let (decoded, _) = YasmfHash::<ArrayVec<[u8; BLAKE3_HASH_SIZE]>>::decode_owned(&encoded).unwrap();
334
335        assert_eq!(decoded, yasmf_hash);
336    }
337}