1use core::cmp;
2use core::fmt;
3
4use alloc::string::String;
5use crypto_common::typenum::Unsigned;
6use crypto_common::OutputSizeUser;
7use rand_core::CryptoRngCore;
8use sha2::{Digest, Sha256};
9
10use crate::error::RnsError;
11
12pub const HASH_SIZE: usize = <<Sha256 as OutputSizeUser>::OutputSize as Unsigned>::USIZE;
13pub const ADDRESS_HASH_SIZE: usize = 16;
14
15pub fn create_hash(data: &[u8], out: &mut [u8]) {
16 out.copy_from_slice(
17 &Sha256::new().chain_update(data).finalize().as_slice()[..cmp::min(out.len(), HASH_SIZE)],
18 );
19}
20
21pub fn address_hash(data: &[u8]) -> [u8; ADDRESS_HASH_SIZE] {
22 let mut hasher = Sha256::new();
23 hasher.update(data);
24 let out = hasher.finalize();
25 let mut truncated = [0u8; ADDRESS_HASH_SIZE];
26 truncated.copy_from_slice(&out[..ADDRESS_HASH_SIZE]);
27 truncated
28}
29
30pub fn lxmf_address_hash(hash: &Hash) -> AddressHash {
31 AddressHash::new_from_hash(hash)
32}
33
34#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
35pub struct Hash([u8; HASH_SIZE]);
36
37#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Hash)]
38pub struct AddressHash([u8; ADDRESS_HASH_SIZE]);
39
40impl Hash {
41 pub fn generator() -> Sha256 {
42 Sha256::new()
43 }
44
45 pub const fn new(hash: [u8; HASH_SIZE]) -> Self {
46 Self(hash)
47 }
48
49 pub const fn new_empty() -> Self {
50 Self([0u8; HASH_SIZE])
51 }
52
53 pub fn new_from_slice(data: &[u8]) -> Self {
54 let mut hash = [0u8; HASH_SIZE];
55 create_hash(data, &mut hash);
56 Self(hash)
57 }
58
59 pub fn new_from_rand<R: CryptoRngCore>(mut rng: R) -> Self {
60 let mut hash = [0u8; HASH_SIZE];
61 let mut data = [0u8; HASH_SIZE];
62
63 rng.fill_bytes(&mut data[..]);
64
65 create_hash(&data, &mut hash);
66 Self(hash)
67 }
68
69 pub fn as_slice(&self) -> &[u8] {
70 &self.0
71 }
72
73 pub fn as_bytes(&self) -> &[u8; HASH_SIZE] {
74 &self.0
75 }
76
77 pub fn to_bytes(&self) -> [u8; HASH_SIZE] {
78 self.0
79 }
80
81 pub fn as_slice_mut(&mut self) -> &mut [u8] {
82 &mut self.0
83 }
84}
85
86impl AddressHash {
87 pub const fn new(hash: [u8; ADDRESS_HASH_SIZE]) -> Self {
88 Self(hash)
89 }
90
91 pub fn new_from_slice(data: &[u8]) -> Self {
92 let mut hash = [0u8; ADDRESS_HASH_SIZE];
93 create_hash(data, &mut hash);
94 Self(hash)
95 }
96
97 pub fn new_from_hash(hash: &Hash) -> Self {
98 let mut address_hash = [0u8; ADDRESS_HASH_SIZE];
99 address_hash.copy_from_slice(&hash.0[0..ADDRESS_HASH_SIZE]);
100 Self(address_hash)
101 }
102
103 pub fn new_from_rand<R: CryptoRngCore>(rng: R) -> Self {
104 Self::new_from_hash(&Hash::new_from_rand(rng))
105 }
106
107 pub fn new_from_hex_string(hex_string: &str) -> Result<Self, RnsError> {
108 if hex_string.len() < ADDRESS_HASH_SIZE * 2 {
109 return Err(RnsError::IncorrectHash);
110 }
111
112 let mut bytes = [0u8; ADDRESS_HASH_SIZE];
113
114 for i in 0..ADDRESS_HASH_SIZE {
115 bytes[i] = u8::from_str_radix(&hex_string[i * 2..(i * 2) + 2], 16)
116 .map_err(|_| RnsError::IncorrectHash)?;
117 }
118
119 Ok(Self(bytes))
120 }
121
122 pub const fn new_empty() -> Self {
123 Self([0u8; ADDRESS_HASH_SIZE])
124 }
125
126 pub fn as_slice(&self) -> &[u8] {
127 &self.0[..]
128 }
129
130 pub fn as_mut_slice(&mut self) -> &mut [u8] {
131 &mut self.0[..]
132 }
133
134 pub const fn len(&self) -> usize {
135 self.0.len()
136 }
137
138 pub fn is_empty(&self) -> bool {
139 self.0.iter().all(|byte| *byte == 0)
140 }
141
142 pub fn to_hex_string(&self) -> String {
143 hex::encode(self.0)
144 }
145}
146
147impl From<Hash> for AddressHash {
148 fn from(hash: Hash) -> Self {
149 Self::new_from_hash(&hash)
150 }
151}
152
153impl Default for AddressHash {
154 fn default() -> Self {
155 Self::new_empty()
156 }
157}
158
159impl fmt::Display for AddressHash {
160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161 write!(f, "/")?;
162 for data in self.0.iter() {
163 write!(f, "{:0>2x}", data)?;
164 }
165 write!(f, "/")?;
166
167 Ok(())
168 }
169}
170
171impl fmt::Display for Hash {
172 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173 for data in self.0.iter() {
174 write!(f, "{:0>2x}", data)?;
175 }
176
177 Ok(())
178 }
179}
180
181#[cfg(test)]
182mod tests {
183
184 use rand_core::OsRng;
185
186 use crate::hash::AddressHash;
187
188 #[test]
189 fn address_hex_string() {
190 let original_address_hash = AddressHash::new_from_rand(OsRng);
191
192 let address_hash_hex = original_address_hash.to_hex_string();
193
194 let actual_address_hash =
195 AddressHash::new_from_hex_string(&address_hash_hex).expect("valid hash");
196
197 assert_eq!(actual_address_hash.as_slice(), original_address_hash.as_slice());
198 }
199}