cardano_crypto/hash/
blake2b.rs

1//! Blake2b hash implementations
2//!
3//! Provides Blake2b variants used in Cardano:
4//! - Blake2b-224 (28 bytes) - Address derivation
5//! - Blake2b-256 (32 bytes) - KES verification keys (matches Haskell)
6//! - Blake2b-512 (64 bytes) - General purpose
7
8use alloc::vec::Vec;
9
10use super::HashAlgorithm;
11use blake2::digest::consts::{U28, U32};
12use blake2::{Blake2b, Digest};
13
14/// Blake2b-224 hash algorithm (28-byte output)
15///
16/// Used in Cardano for address derivation and verification key hashing.
17/// This matches `Cardano.Crypto.Hash.Blake2b_224` from cardano-base.
18///
19/// # Example
20///
21/// ```rust
22/// use cardano_crypto::hash::{HashAlgorithm, Blake2b224};
23///
24/// let data = b"Cardano address data";
25/// let hash = Blake2b224::hash(data);
26/// assert_eq!(hash.len(), Blake2b224::OUTPUT_SIZE); // 28 bytes
27/// ```
28#[derive(Clone, Debug)]
29pub struct Blake2b224;
30
31impl HashAlgorithm for Blake2b224 {
32    const OUTPUT_SIZE: usize = 28;
33    const ALGORITHM_NAME: &'static str = "blake2b_224";
34
35    #[inline]
36    fn hash(data: &[u8]) -> Vec<u8> {
37        let mut hasher = Blake2b::<U28>::new();
38        hasher.update(data);
39        hasher.finalize().to_vec()
40    }
41}
42
43/// Blake2b-256 hash algorithm (32-byte output)
44///
45/// This is the hash algorithm used in Haskell's cardano-base for KES Sum types.
46/// Critical for binary compatibility with Cardano node verification keys.
47///
48/// # Example
49///
50/// ```rust
51/// use cardano_crypto::hash::{HashAlgorithm, Blake2b256};
52///
53/// let vkey_data = b"KES verification key data";
54/// let hash = Blake2b256::hash(vkey_data);
55/// assert_eq!(hash.len(), 32);
56/// assert_eq!(Blake2b256::ALGORITHM_NAME, "blake2b_256");
57/// ```
58#[derive(Clone, Debug)]
59pub struct Blake2b256;
60
61impl HashAlgorithm for Blake2b256 {
62    const OUTPUT_SIZE: usize = 32;
63    const ALGORITHM_NAME: &'static str = "blake2b_256";
64
65    #[inline]
66    fn hash(data: &[u8]) -> Vec<u8> {
67        let mut hasher = Blake2b::<U32>::new();
68        hasher.update(data);
69        hasher.finalize().to_vec()
70    }
71}
72
73/// Blake2b-512 hash algorithm (64-byte output)
74///
75/// General purpose Blake2b with maximum output size.
76/// Used for compatibility with existing code.
77///
78/// # Example
79///
80/// ```rust
81/// use cardano_crypto::hash::{HashAlgorithm, Blake2b512};
82///
83/// let data = b"Large data for 64-byte hash";
84/// let hash = Blake2b512::hash(data);
85/// assert_eq!(hash.len(), 64);
86/// ```
87#[derive(Clone, Debug)]
88pub struct Blake2b512;
89
90impl HashAlgorithm for Blake2b512 {
91    const OUTPUT_SIZE: usize = 64;
92    const ALGORITHM_NAME: &'static str = "blake2b_512";
93
94    #[inline]
95    fn hash(data: &[u8]) -> Vec<u8> {
96        use blake2::Blake2b512 as Blake2b512Hasher;
97
98        let mut hasher = Blake2b512Hasher::new();
99        hasher.update(data);
100        hasher.finalize().to_vec()
101    }
102}
103
104/// Standalone Blake2b-224 hash function (28 bytes output)
105///
106/// Convenience function matching the trait implementation.
107#[must_use]
108#[allow(dead_code)]
109pub(crate) fn blake2b224(data: &[u8]) -> [u8; 28] {
110    let mut hasher = Blake2b::<U28>::new();
111    hasher.update(data);
112    hasher.finalize().into()
113}
114
115/// Standalone Blake2b-256 hash function (32 bytes output)
116///
117/// Convenience function matching the trait implementation.
118#[must_use]
119#[allow(dead_code)]
120pub(crate) fn blake2b256(data: &[u8]) -> [u8; 32] {
121    let mut hasher = Blake2b::<U32>::new();
122    hasher.update(data);
123    hasher.finalize().into()
124}
125
126/// Standalone Blake2b-512 hash function (64 bytes output)
127///
128/// Convenience function matching the trait implementation.
129#[must_use]
130#[allow(dead_code)]
131pub(crate) fn blake2b512(data: &[u8]) -> [u8; 64] {
132    use blake2::Blake2b512 as Blake2b512Hasher;
133
134    let mut hasher = Blake2b512Hasher::new();
135    hasher.update(data);
136    hasher.finalize().into()
137}
138
139#[cfg(test)]
140mod tests {
141    use super::*;
142
143    #[test]
144    fn test_blake2b224_empty() {
145        let expected = "836cc68931c2e4e3e838602eca1902591d216837bafddfe6f0c8cb07";
146        let out = Blake2b224::hash(b"");
147        assert_eq!(hex::encode(out), expected);
148    }
149
150    #[test]
151    fn test_blake2b224_hello_world() {
152        let expected = "42d1854b7d69e3b57c64fcc7b4f64171b47dff43fba6ac0499ff437f";
153        let out = Blake2b224::hash(b"hello world");
154        assert_eq!(hex::encode(out), expected);
155    }
156
157    #[test]
158    fn test_blake2b256_empty() {
159        let expected = "0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8";
160        let out = Blake2b256::hash(b"");
161        assert_eq!(hex::encode(out), expected);
162    }
163
164    #[test]
165    fn test_blake2b256_hello_world() {
166        let expected = "256c83b297114d201b30179f3f0ef0cace9783622da5974326b436178aeef610";
167        let out = Blake2b256::hash(b"hello world");
168        assert_eq!(hex::encode(out), expected);
169    }
170
171    #[test]
172    fn test_blake2b512_empty() {
173        let expected = "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce";
174        let out = Blake2b512::hash(b"");
175        assert_eq!(hex::encode(out), expected);
176    }
177
178    #[test]
179    fn test_blake2b512_hello_world() {
180        let expected = "021ced8799296ceca557832ab941a50b4a11f83478cf141f51f933f653ab9fbcc05a037cddbed06e309bf334942c4e58cdf1a46e237911ccd7fcf9787cbc7fd0";
181        let out = Blake2b512::hash(b"hello world");
182        assert_eq!(hex::encode(out), expected);
183    }
184
185    #[test]
186    fn test_hash_concat() {
187        let data1 = b"hello";
188        let data2 = b"world";
189        let hash1 = Blake2b256::hash_concat(data1, data2);
190        let hash2 = Blake2b256::hash(b"helloworld");
191        assert_eq!(hash1, hash2);
192    }
193
194    #[test]
195    fn test_expand_seed() {
196        let seed = b"test seed";
197        let (seed0, seed1) = Blake2b256::expand_seed(seed);
198        assert_eq!(seed0.len(), 32);
199        assert_eq!(seed1.len(), 32);
200        assert_ne!(seed0, seed1, "Expanded seeds should be different");
201    }
202
203    #[test]
204    fn test_blake2b256_not_simple_truncation() {
205        let cases = [
206            b"".as_ref(),
207            b"cardano".as_ref(),
208            b"longer-message".as_ref(),
209        ];
210
211        for input in cases {
212            let blake512 = Blake2b512::hash(input);
213            let blake256 = Blake2b256::hash(input);
214            assert_ne!(&blake512[..32], &blake256[..]);
215        }
216    }
217
218    #[test]
219    fn test_blake2b224_not_truncation() {
220        let cases = [
221            b"".as_ref(),
222            b"address-key".as_ref(),
223            b"longer-message".as_ref(),
224        ];
225
226        for input in cases {
227            let blake512 = Blake2b512::hash(input);
228            let blake224 = Blake2b224::hash(input);
229            assert_ne!(&blake512[..28], &blake224[..]);
230
231            let blake256 = Blake2b256::hash(input);
232            assert_ne!(&blake256[..28], &blake224[..]);
233        }
234    }
235}
236
237// Helper for hex encoding in tests
238#[cfg(test)]
239mod hex {
240    pub(crate) fn encode(bytes: impl AsRef<[u8]>) -> String {
241        bytes
242            .as_ref()
243            .iter()
244            .map(|b| format!("{:02x}", b))
245            .collect()
246    }
247}