integrationos_domain/algebra/
hash.rs

1use crate::{hashed_secret::HashedSecret, IntegrationOSError, InternalError};
2use serde_json::Value;
3use sha3::{Digest, Keccak256};
4
5pub trait HashExt {
6    fn hash(&self, value: &str) -> Result<String, IntegrationOSError>;
7    fn verify(&self, value: &str, hash: &str) -> bool;
8}
9
10pub struct HashKecAlg;
11
12impl HashKecAlg {
13    pub fn new() -> Self {
14        HashKecAlg
15    }
16}
17
18impl Default for HashKecAlg {
19    fn default() -> Self {
20        Self::new()
21    }
22}
23
24impl HashExt for HashKecAlg {
25    fn hash(&self, value: &str) -> Result<String, IntegrationOSError> {
26        let mut hasher = Keccak256::new();
27        hasher.update(value);
28        Ok(format!("{:x}", hasher.finalize()))
29    }
30
31    fn verify(&self, value: &str, hash: &str) -> bool {
32        self.hash(value).ok().map_or(false, |h| h == hash)
33    }
34}
35
36impl TryFrom<Value> for HashedSecret {
37    type Error = IntegrationOSError;
38
39    fn try_from(value: Value) -> Result<Self, Self::Error> {
40        let value_str = serde_json::to_string(&value).map_err(|err| {
41            InternalError::serialize_error(&format!("Failed to serialize value: {err}"), None)
42        })?;
43        let hash = HashKecAlg::new().hash(&value_str)?;
44        Ok(HashedSecret::new(hash))
45    }
46}
47
48#[cfg(test)]
49mod test {
50    use super::*;
51    use serde_json::json;
52
53    #[test]
54    fn test_keccak256_hash() {
55        let value = json!({
56            "response": {
57                "user": {
58                    "name": "Alice",
59                    "age": 3
60                }
61            }
62        });
63
64        let hash = HashKecAlg::new().hash(&value.to_string()).unwrap();
65
66        assert_eq!(
67            hash,
68            "eb42c0c05a0ac6cd15e4cf907a6aa913ebfe6aea79ee7edd054b519435f827cb"
69        );
70    }
71
72    #[test]
73    fn test_keccak256_verify() {
74        let value = json!({
75            "response": {
76                "user": {
77                    "name": "Alice",
78                    "age": 3
79                }
80            }
81        });
82
83        let hash = HashKecAlg::new().hash(&value.to_string()).unwrap();
84
85        assert!(HashKecAlg::new().verify(&value.to_string(), &hash));
86    }
87
88    #[test]
89    fn test_hash_from_value() {
90        let value = json!({
91            "response": {
92                "user": {
93                    "name": "Alice",
94                    "age": 3
95                }
96            }
97        });
98
99        let hash = HashedSecret::try_from(value).unwrap();
100
101        assert_eq!(
102            hash.inner(),
103            "eb42c0c05a0ac6cd15e4cf907a6aa913ebfe6aea79ee7edd054b519435f827cb"
104        );
105    }
106}