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}