cardano_crypto/hash/mod.rs
1//! Hash functions used in Cardano cryptography
2//!
3//! This module provides hash functions required for Cardano protocols:
4//!
5//! - [`Blake2b224`] - 28-byte Blake2b hash (used in address derivation)
6//! - [`Blake2b256`] - 32-byte Blake2b hash (used in KES verification keys)
7//! - [`Blake2b512`] - 64-byte Blake2b hash (general purpose)
8//! - Additional cross-chain hashes (SHA-256, SHA-512, etc.) for compatibility
9//!
10//! # Examples
11//!
12//! ```
13//! use cardano_crypto::hash::{Blake2b256, HashAlgorithm};
14//!
15//! // Hash some data
16//! let data = b"Cardano blockchain data";
17//! let hash = Blake2b256::hash(data);
18//! assert_eq!(hash.len(), 32);
19//!
20//! // Hash concatenated data
21//! let hash = Blake2b256::hash_concat(b"part1", b"part2");
22//! assert_eq!(hash.len(), 32);
23//! ```
24
25use alloc::vec::Vec;
26
27mod blake2b;
28mod sha;
29
30// Re-export hash implementations
31pub use blake2b::{Blake2b224, Blake2b256, Blake2b512};
32pub use sha::{hash160, keccak256, ripemd160, sha256, sha256d, sha3_256, sha3_512, sha512};
33
34/// Trait for hash algorithms used in KES schemes
35///
36/// This trait provides a simple interface for hash algorithms used in
37/// Key Evolving Signature (KES) constructions, particularly for the
38/// binary sum composition where verification keys are hashed.
39pub trait HashAlgorithm: Clone + Send + Sync + 'static {
40 /// Output size in bytes
41 const OUTPUT_SIZE: usize;
42
43 /// Algorithm name for debugging
44 const ALGORITHM_NAME: &'static str;
45
46 /// Hash the input data
47 ///
48 /// # Example
49 ///
50 /// ```
51 /// use cardano_crypto::hash::{Blake2b256, HashAlgorithm};
52 ///
53 /// let data = b"input data";
54 /// let hash = Blake2b256::hash(data);
55 /// assert_eq!(hash.len(), Blake2b256::OUTPUT_SIZE);
56 /// ```
57 fn hash(data: &[u8]) -> Vec<u8>;
58
59 /// Hash two inputs concatenated together
60 ///
61 /// # Example
62 ///
63 /// ```
64 /// use cardano_crypto::hash::{Blake2b256, HashAlgorithm};
65 ///
66 /// let hash = Blake2b256::hash_concat(b"hello", b"world");
67 /// assert_eq!(hash.len(), 32);
68 /// ```
69 fn hash_concat(data1: &[u8], data2: &[u8]) -> Vec<u8> {
70 let mut combined = Vec::with_capacity(data1.len() + data2.len());
71 combined.extend_from_slice(data1);
72 combined.extend_from_slice(data2);
73 Self::hash(&combined)
74 }
75
76 /// Expand a seed into two new seeds using domain separation
77 ///
78 /// # Example
79 ///
80 /// ```
81 /// use cardano_crypto::hash::{Blake2b256, HashAlgorithm};
82 ///
83 /// let seed = b"original seed";
84 /// let (seed0, seed1) = Blake2b256::expand_seed(seed);
85 /// assert_eq!(seed0.len(), 32);
86 /// assert_eq!(seed1.len(), 32);
87 /// assert_ne!(seed0, seed1);
88 /// ```
89 fn expand_seed(seed: &[u8]) -> (Vec<u8>, Vec<u8>) {
90 let mut seed0_input = Vec::with_capacity(seed.len() + 1);
91 seed0_input.extend_from_slice(seed);
92 seed0_input.push(0);
93 let seed0 = Self::hash(&seed0_input);
94
95 let mut seed1_input = Vec::with_capacity(seed.len() + 1);
96 seed1_input.extend_from_slice(seed);
97 seed1_input.push(1);
98 let seed1 = Self::hash(&seed1_input);
99
100 (seed0, seed1)
101 }
102}
103
104/// Constant-time equality over raw hash byte slices
105///
106/// Returns `false` if the inputs differ in length. When lengths match, the
107/// comparison is performed in constant time to prevent timing attacks.
108///
109/// # Example
110///
111/// ```
112/// use cardano_crypto::hash::constant_time_eq;
113///
114/// let hash1 = b"same hash value";
115/// let hash2 = b"same hash value";
116/// let hash3 = b"different value";
117/// assert!(constant_time_eq(hash1, hash2));
118/// assert!(!constant_time_eq(hash1, hash3));
119/// ```
120#[must_use]
121pub fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
122 use subtle::ConstantTimeEq as _;
123
124 if a.len() != b.len() {
125 return false;
126 }
127
128 a.ct_eq(b).into()
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn test_constant_time_eq() {
137 assert!(constant_time_eq(b"hello", b"hello"));
138 assert!(!constant_time_eq(b"hello", b"world"));
139 assert!(!constant_time_eq(b"short", b"longer"));
140 }
141
142 #[test]
143 fn test_all_hash_lengths() {
144 let data = b"test data";
145
146 assert_eq!(sha256(data).len(), 32);
147 assert_eq!(sha256d(data).len(), 32);
148 assert_eq!(sha512(data).len(), 64);
149 assert_eq!(sha3_256(data).len(), 32);
150 assert_eq!(sha3_512(data).len(), 64);
151 assert_eq!(keccak256(data).len(), 32);
152 assert_eq!(ripemd160(data).len(), 20);
153 assert_eq!(hash160(data).len(), 20);
154 }
155
156 #[test]
157 fn test_blake2b_output_lengths() {
158 let inputs = [b"".as_ref(), b"cardano".as_ref(), b"hash-length".as_ref()];
159
160 for input in inputs {
161 assert_eq!(Blake2b224::hash(input).len(), 28);
162 assert_eq!(Blake2b256::hash(input).len(), 32);
163 assert_eq!(Blake2b512::hash(input).len(), 64);
164 }
165 }
166}