accumulate_client/codec/
hash_helper.rs

1//! High-level hash helper utilities
2//!
3//! This module provides convenient wrapper functions around the core hashing implementation
4//! to match the API expected by test files and provide TypeScript SDK compatibility.
5
6use crate::codec::{canonical_json, sha256_bytes};
7use serde_json::Value;
8
9/// High-level hash helper providing convenient hashing operations
10#[derive(Debug, Clone, Copy)]
11pub struct HashHelper;
12
13impl HashHelper {
14    /// Compute SHA-256 hash of raw bytes
15    pub fn sha256(data: &[u8]) -> [u8; 32] {
16        sha256_bytes(data)
17    }
18
19    /// Compute SHA-256 hash of raw bytes and return as hex string
20    pub fn sha256_hex(data: &[u8]) -> String {
21        hex::encode(sha256_bytes(data))
22    }
23
24    /// Compute SHA-256 hash of JSON data
25    pub fn sha256_json(json_data: &Value) -> [u8; 32] {
26        let canonical = canonical_json(json_data);
27        sha256_bytes(canonical.as_bytes())
28    }
29
30    /// Compute SHA-256 hash of JSON data and return as hex string
31    pub fn sha256_json_hex(json_data: &Value) -> String {
32        let canonical = canonical_json(json_data);
33        hex::encode(sha256_bytes(canonical.as_bytes()))
34    }
35
36    /// Convert bytes to hex string
37    pub fn bytes_to_hex(bytes: &[u8]) -> String {
38        hex::encode(bytes)
39    }
40
41    /// Convert hex string to bytes
42    pub fn hex_to_bytes(hex_str: &str) -> Result<Vec<u8>, hex::FromHexError> {
43        hex::decode(hex_str)
44    }
45
46    /// Compute hash of string data
47    pub fn hash_string(data: &str) -> [u8; 32] {
48        sha256_bytes(data.as_bytes())
49    }
50
51    /// Compute hash of string data and return as hex
52    pub fn hash_string_hex(data: &str) -> String {
53        hex::encode(sha256_bytes(data.as_bytes()))
54    }
55
56    /// Create a double hash (hash of hash)
57    pub fn double_hash(data: &[u8]) -> [u8; 32] {
58        let first_hash = sha256_bytes(data);
59        sha256_bytes(&first_hash)
60    }
61
62    /// Create a double hash and return as hex
63    pub fn double_hash_hex(data: &[u8]) -> String {
64        hex::encode(Self::double_hash(data))
65    }
66
67    /// Verify that two byte arrays are equal
68    pub fn bytes_equal(a: &[u8], b: &[u8]) -> bool {
69        a == b
70    }
71
72    /// Verify hash matches expected value
73    pub fn verify_hash(data: &[u8], expected_hash: &[u8; 32]) -> bool {
74        &sha256_bytes(data) == expected_hash
75    }
76
77    /// Verify hash matches expected hex value
78    pub fn verify_hash_hex(data: &[u8], expected_hex: &str) -> bool {
79        let computed_hash = hex::encode(sha256_bytes(data));
80        computed_hash == expected_hex
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87    use serde_json::json;
88
89    #[test]
90    fn test_sha256_basic() {
91        let data = b"Hello, World!";
92        let hash = HashHelper::sha256(data);
93        let hash_hex = HashHelper::sha256_hex(data);
94
95        assert_eq!(hash.len(), 32);
96        assert_eq!(hash_hex.len(), 64);
97        assert_eq!(hash_hex, hex::encode(hash));
98    }
99
100    #[test]
101    fn test_json_hashing() {
102        let json_data = json!({
103            "test": "data",
104            "number": 42
105        });
106
107        let hash = HashHelper::sha256_json(&json_data);
108        let hash_hex = HashHelper::sha256_json_hex(&json_data);
109
110        assert_eq!(hash.len(), 32);
111        assert_eq!(hash_hex, hex::encode(hash));
112    }
113
114    #[test]
115    fn test_deterministic_json_hashing() {
116        let json1 = json!({"b": 2, "a": 1});
117        let json2 = json!({"a": 1, "b": 2});
118
119        let hash1 = HashHelper::sha256_json_hex(&json1);
120        let hash2 = HashHelper::sha256_json_hex(&json2);
121
122        // Should be the same due to canonical ordering
123        assert_eq!(hash1, hash2);
124    }
125
126    #[test]
127    fn test_double_hash() {
128        let data = b"test data";
129        let single_hash = HashHelper::sha256(data);
130        let double_hash = HashHelper::double_hash(data);
131
132        // Double hash should be different from single hash
133        assert_ne!(single_hash, double_hash);
134
135        // Verify double hash is hash of hash
136        let expected_double = HashHelper::sha256(&single_hash);
137        assert_eq!(double_hash, expected_double);
138    }
139
140    #[test]
141    fn test_hex_conversion() {
142        let data = b"test";
143        let hex = HashHelper::bytes_to_hex(data);
144        let bytes_back = HashHelper::hex_to_bytes(&hex).unwrap();
145
146        assert_eq!(data, &bytes_back[..]);
147    }
148
149    #[test]
150    fn test_hash_verification() {
151        let data = b"verification test";
152        let hash = HashHelper::sha256(data);
153        let hash_hex = HashHelper::sha256_hex(data);
154
155        assert!(HashHelper::verify_hash(data, &hash));
156        assert!(HashHelper::verify_hash_hex(data, &hash_hex));
157
158        // Test with wrong data
159        assert!(!HashHelper::verify_hash(b"wrong data", &hash));
160        assert!(!HashHelper::verify_hash_hex(b"wrong data", &hash_hex));
161    }
162}