Skip to main content

rns_core/
hash.rs

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}