clock_hash/
domain.rs

1//! Domain separation for ClockHash-256
2//!
3//! Domain separation ensures that hashes computed for different use cases
4//! (block headers, transactions, Merkle trees, etc.) produce different outputs
5//! even when the input data is identical. This prevents cross-domain collision
6//! attacks and maintains the security properties of the hash function.
7//!
8//! ## Security Importance
9//!
10//! Without domain separation, an attacker who finds a collision in one domain
11//! could potentially use it to attack a different domain. Domain separation
12//! ensures that collisions in one domain have no impact on others.
13//!
14//! ## Implementation
15//!
16//! Domain separation is implemented by prepending the domain identifier
17//! followed by a null byte separator before the actual data:
18//!
19//! `hash(domain || 0x00 || data)`
20//!
21//! This approach is simple, efficient, and provides strong separation guarantees.
22
23use crate::hasher::ClockHasher;
24
25/// Predefined domain tag constants for ClockinChain use cases
26///
27/// These constants define the standard domain separators used throughout
28/// the ClockinChain ecosystem. Each domain serves a specific purpose and
29/// ensures isolation between different hash applications.
30pub mod tags {
31    /// Domain tag for block headers
32    ///
33    /// Used for hashing complete block headers including previous hash,
34    /// merkle root, timestamp, difficulty, and nonce.
35    ///
36    /// # Example
37    /// ```rust
38    /// # use clock_hash::{clockhash256_domain, tags};
39    /// let block_header = b"prev_hash|merkle_root|timestamp|difficulty|nonce";
40    /// let block_hash = clockhash256_domain(tags::CLK_BLOCK, block_header);
41    /// ```
42    pub const CLK_BLOCK: &[u8] = b"CLK-BLOCK";
43
44    /// Domain tag for transaction identifiers
45    ///
46    /// Used for computing transaction IDs from transaction data including
47    /// inputs, outputs, lock time, and other metadata.
48    ///
49    /// # Example
50    /// ```rust
51    /// # use clock_hash::{clockhash256_domain, tags};
52    /// let tx_data = b"inputs|outputs|lock_time|version";
53    /// let tx_id = clockhash256_domain(tags::CLK_TX, tx_data);
54    /// ```
55    pub const CLK_TX: &[u8] = b"CLK-TX";
56
57    /// Domain tag for Merkle tree nodes
58    ///
59    /// Used for constructing Merkle trees where internal nodes are hashes
60    /// of concatenated child hashes.
61    ///
62    /// # Example
63    /// ```rust
64    /// # use clock_hash::{clockhash256_domain, tags};
65    /// let left_data = b"left child data";
66    /// let right_data = b"right child data";
67    /// let left_hash = clockhash256_domain(tags::CLK_MERKLE, left_data);
68    /// let right_hash = clockhash256_domain(tags::CLK_MERKLE, right_data);
69    /// let parent_data = [left_hash, right_hash].concat();
70    /// let parent_hash = clockhash256_domain(tags::CLK_MERKLE, &parent_data);
71    /// ```
72    pub const CLK_MERKLE: &[u8] = b"CLK-MERKLE";
73
74    /// Domain tag for signature nonce derivation
75    ///
76    /// Used for deterministic nonce generation in digital signatures to
77    /// prevent nonce reuse attacks while maintaining deterministic behavior.
78    ///
79    /// # Example
80    /// ```rust
81    /// # use clock_hash::{clockhash256_domain, tags};
82    /// let nonce_seed = b"private_key|message_hash|counter";
83    /// let nonce = clockhash256_domain(tags::CLK_NONCE, nonce_seed);
84    /// ```
85    pub const CLK_NONCE: &[u8] = b"CLK-NONCE";
86
87    /// Domain tag for deterministic random number generation
88    ///
89    /// Used for seeding deterministic RNGs that need cryptographic strength
90    /// and domain isolation from other random number uses.
91    ///
92    /// # Example
93    /// ```rust
94    /// # use clock_hash::{clockhash256_domain, tags};
95    /// let rng_seed = b"user_entropy|domain_info|counter";
96    /// let rng_key = clockhash256_domain(tags::CLK_RNG, rng_seed);
97    /// ```
98    pub const CLK_RNG: &[u8] = b"CLK-RNG";
99}
100
101/// Type-safe domain tag enumeration for ClockinChain use cases
102///
103/// `DomainTag` provides compile-time type safety for domain separation.
104/// Each variant corresponds to a specific use case and maps to the
105/// appropriate domain tag bytes. This prevents typos and ensures
106/// consistent domain usage across the codebase.
107///
108/// # Examples
109///
110/// Using with typed domains:
111/// ```rust
112/// use clock_hash::{clockhash256_with_domain, DomainTag};
113///
114/// let block_data = b"block header data";
115/// let tx_data = b"transaction data";
116///
117/// let block_hash = clockhash256_with_domain(DomainTag::Block, block_data);
118/// let tx_hash = clockhash256_with_domain(DomainTag::Transaction, tx_data);
119///
120/// assert_ne!(block_hash, tx_hash); // Guaranteed to be different
121/// ```
122///
123/// Converting to bytes:
124/// ```rust
125/// # use clock_hash::DomainTag;
126/// let tag = DomainTag::Merkle;
127/// let bytes = tag.as_bytes();
128/// assert_eq!(bytes, b"CLK-MERKLE");
129/// ```
130#[derive(Clone, Copy, Debug, PartialEq, Eq)]
131pub enum DomainTag {
132    /// Block header hashing domain
133    ///
134    /// For hashing complete block headers in the blockchain
135    Block,
136    /// Transaction identifier domain
137    ///
138    /// For computing unique transaction IDs
139    Transaction,
140    /// Merkle tree construction domain
141    ///
142    /// For building Merkle trees and computing merkle roots
143    Merkle,
144    /// Signature nonce derivation domain
145    ///
146    /// For deterministic nonce generation in signatures
147    Nonce,
148    /// Deterministic RNG seeding domain
149    ///
150    /// For seeding cryptographic random number generators
151    Rng,
152}
153
154impl DomainTag {
155    /// Get the byte representation of the domain tag
156    #[inline]
157    pub fn as_bytes(self) -> &'static [u8] {
158        match self {
159            DomainTag::Block => tags::CLK_BLOCK,
160            DomainTag::Transaction => tags::CLK_TX,
161            DomainTag::Merkle => tags::CLK_MERKLE,
162            DomainTag::Nonce => tags::CLK_NONCE,
163            DomainTag::Rng => tags::CLK_RNG,
164        }
165    }
166}
167
168/// Compute ClockHash-256 with custom domain separation.
169///
170/// This function provides domain separation by prepending the domain identifier
171/// followed by a null byte separator before hashing the actual data. This ensures
172/// that identical data produces different hashes when used in different domains,
173/// preventing cross-domain collision attacks.
174///
175/// # Arguments
176///
177/// * `domain` - Custom domain identifier bytes (must be consistent for the same domain)
178/// * `data` - The data to hash
179///
180/// # Returns
181///
182/// A 32-byte array containing the domain-separated ClockHash-256 hash
183///
184/// # Examples
185///
186/// Using custom domain tags:
187/// ```rust
188/// # use clock_hash::clockhash256_domain;
189/// let data = b"some data";
190///
191/// let domain1 = b"MY-APP-V1";
192/// let domain2 = b"MY-APP-V2";
193///
194/// let hash1 = clockhash256_domain(domain1, data);
195/// let hash2 = clockhash256_domain(domain2, data);
196///
197/// assert_ne!(hash1, hash2); // Different domains = different hashes
198/// ```
199///
200/// Custom domain vs no domain:
201/// ```rust
202/// # use clock_hash::{clockhash256_domain, clockhash256};
203/// let data = b"test";
204/// let custom_hash = clockhash256_domain(b"CUSTOM", data);
205/// let plain_hash = clockhash256(data);
206///
207/// assert_ne!(custom_hash, plain_hash); // Domain separation works
208/// ```
209///
210/// # Security Notes
211///
212/// - Domain identifiers should be unique and consistent within your application
213/// - Never use the same domain for different purposes
214/// - Domain separation is critical for maintaining hash function security properties
215#[inline]
216pub fn clockhash256_domain(domain: &[u8], data: &[u8]) -> [u8; 32] {
217    let mut hasher = ClockHasher::new();
218
219    // Prepend domain tag and separator to achieve domain separation
220    // Format: domain || 0x00 || data
221    hasher.update(domain);
222    hasher.update(&[0x00]);
223    hasher.update(data);
224
225    hasher.finalize()
226}
227
228/// Compute ClockHash-256 with a typed domain tag.
229///
230/// This function provides type-safe domain separation using the `DomainTag` enum.
231/// It automatically converts the enum variant to the appropriate domain bytes
232/// and performs domain-separated hashing.
233///
234/// # Arguments
235///
236/// * `domain` - The domain tag enum variant specifying the use case
237/// * `data` - The data to hash
238///
239/// # Returns
240///
241/// A 32-byte array containing the domain-separated ClockHash-256 hash
242///
243/// # Examples
244///
245/// Type-safe domain hashing:
246/// ```rust
247/// use clock_hash::{clockhash256_with_domain, DomainTag};
248///
249/// let data = b"important data";
250///
251/// // Type-safe domain specification
252/// let block_hash = clockhash256_with_domain(DomainTag::Block, data);
253/// let merkle_hash = clockhash256_with_domain(DomainTag::Merkle, data);
254///
255/// assert_ne!(block_hash, merkle_hash);
256/// ```
257///
258/// All domain types:
259/// ```rust
260/// # use clock_hash::{clockhash256_with_domain, DomainTag};
261/// # let data = b"test";
262/// let block_hash = clockhash256_with_domain(DomainTag::Block, data);
263/// let tx_hash = clockhash256_with_domain(DomainTag::Transaction, data);
264/// let merkle_hash = clockhash256_with_domain(DomainTag::Merkle, data);
265/// let nonce_hash = clockhash256_with_domain(DomainTag::Nonce, data);
266/// let rng_hash = clockhash256_with_domain(DomainTag::Rng, data);
267///
268/// // All hashes are guaranteed to be different
269/// let hashes = vec![block_hash, tx_hash, merkle_hash, nonce_hash, rng_hash];
270/// for i in 0..hashes.len() {
271///     for j in (i+1)..hashes.len() {
272///         assert_ne!(hashes[i], hashes[j]);
273///     }
274/// }
275/// ```
276///
277/// # Performance
278///
279/// This function has the same performance characteristics as `clockhash256_domain()`
280/// since it simply delegates to that function after converting the enum to bytes.
281#[inline]
282pub fn clockhash256_with_domain(domain: DomainTag, data: &[u8]) -> [u8; 32] {
283    clockhash256_domain(domain.as_bytes(), data)
284}
285
286#[cfg(test)]
287mod tests {
288    use super::*;
289    use crate::clockhash256;
290
291    #[test]
292    fn test_domain_separation() {
293        let data = b"test data";
294
295        // Different domains should produce different hashes
296        let hash1 = clockhash256_domain(tags::CLK_BLOCK, data);
297        let hash2 = clockhash256_domain(tags::CLK_TX, data);
298        let hash3 = clockhash256(data);
299
300        assert_ne!(
301            hash1, hash2,
302            "Different domains should produce different hashes"
303        );
304        assert_ne!(
305            hash1, hash3,
306            "Domain-separated hash should differ from raw hash"
307        );
308        assert_ne!(
309            hash2, hash3,
310            "Domain-separated hash should differ from raw hash"
311        );
312    }
313
314    #[test]
315    fn test_domain_tag_enum() {
316        let data = b"test";
317
318        let hash_block = clockhash256_with_domain(DomainTag::Block, data);
319        let hash_tx = clockhash256_with_domain(DomainTag::Transaction, data);
320        let hash_merkle = clockhash256_with_domain(DomainTag::Merkle, data);
321
322        assert_ne!(hash_block, hash_tx);
323        assert_ne!(hash_block, hash_merkle);
324        assert_ne!(hash_tx, hash_merkle);
325    }
326
327    #[test]
328    fn test_domain_deterministic() {
329        let data = b"deterministic test";
330
331        let hash1 = clockhash256_domain(tags::CLK_BLOCK, data);
332        let hash2 = clockhash256_domain(tags::CLK_BLOCK, data);
333
334        assert_eq!(
335            hash1, hash2,
336            "Same domain and data should produce same hash"
337        );
338    }
339}