Skip to main content

axone_objectarium/
crypto.rs

1use cosmwasm_std::{StdError, StdResult};
2use cw_storage_plus::{Key, KeyDeserialize, Prefixer, PrimaryKey};
3use md5;
4use schemars::JsonSchema;
5use serde::{Deserialize, Serialize};
6use sha2;
7use sha2::Digest;
8use std::any::type_name;
9use std::fmt;
10
11/// HashAlgorithm is the type of the hash algorithm.
12pub enum HashAlgorithm {
13    /// Represents the MD5 algorithm.
14    MD5,
15    /// Represents the SHA-224 algorithm.
16    Sha224,
17    /// Represents the SHA-256 algorithm.
18    Sha256,
19    /// Represents the SHA-384 algorithm.
20    Sha384,
21    /// Represents the SHA-512 algorithm.
22    Sha512,
23}
24
25impl HashAlgorithm {
26    /// hash returns the hash of the given data using the given algorithm.
27    pub fn hash_fn(&self) -> HashFn {
28        match self {
29            HashAlgorithm::MD5 => md5_hash,
30            HashAlgorithm::Sha224 => sha224_hash,
31            HashAlgorithm::Sha256 => sha256_hash,
32            HashAlgorithm::Sha384 => sha384_hash,
33            HashAlgorithm::Sha512 => sha512_hash,
34        }
35    }
36}
37
38/// Hash represent a Object hash as binary value.
39#[derive(
40    Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, JsonSchema,
41)]
42pub struct Hash(Vec<u8>);
43
44/// HashFn is the type of the function used to hash data.
45pub type HashFn = fn(&Vec<u8>) -> Hash;
46
47/// hash returns the hash of the given data using the given algorithm.
48pub fn hash<'a>(algorithm: &'a HashAlgorithm, data: &'a Vec<u8>) -> Hash {
49    algorithm.hash_fn()(data)
50}
51
52/// md5_hash returns the MD5 hash of the given data.
53fn md5_hash(data: &Vec<u8>) -> Hash {
54    md5::Md5::digest(data).to_vec().into()
55}
56
57/// sha224_hash returns the SHA-224 hash of the given data.
58fn sha224_hash(data: &Vec<u8>) -> Hash {
59    sha2::Sha224::digest(data).to_vec().into()
60}
61
62/// sha256_hash returns the SHA-256 hash of the given data.
63fn sha256_hash(data: &Vec<u8>) -> Hash {
64    sha2::Sha256::digest(data).to_vec().into()
65}
66
67/// sha384_hash returns the SHA-384 hash of the given data.
68fn sha384_hash(data: &Vec<u8>) -> Hash {
69    sha2::Sha384::digest(data).to_vec().into()
70}
71
72/// sha512_hash returns the SHA-512 hash of the given data.
73fn sha512_hash(data: &Vec<u8>) -> Hash {
74    sha2::Sha512::digest(data).to_vec().into()
75}
76
77impl TryFrom<String> for Hash {
78    type Error = StdError;
79
80    fn try_from(s: String) -> StdResult<Hash> {
81        base16ct::lower::decode_vec(s)
82            .map_err(|e| StdError::parse_err(type_name::<Vec<u8>>(), e.to_string()))
83            .map(Hash)
84    }
85}
86
87// Allows for a (user-friendly) string representation of Hash as a lower Base16 (hex) encoding.
88impl fmt::Display for Hash {
89    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90        let hex_string = base16ct::lower::encode_string(&self.0);
91        write!(f, "{}", hex_string)
92    }
93}
94
95impl From<Vec<u8>> for Hash {
96    fn from(hash: Vec<u8>) -> Self {
97        Hash(hash)
98    }
99}
100
101impl From<Hash> for Vec<u8> {
102    fn from(hash: Hash) -> Self {
103        hash.0
104    }
105}
106
107impl From<&Hash> for Vec<u8> {
108    fn from(hash: &Hash) -> Self {
109        hash.0.clone()
110    }
111}
112
113impl<'a> PrimaryKey<'a> for Hash {
114    type Prefix = ();
115    type SubPrefix = ();
116    type Suffix = Self;
117    type SuperSuffix = Self;
118
119    fn key(&self) -> Vec<Key<'_>> {
120        vec![Key::Ref(self.0.as_ref())]
121    }
122}
123
124impl KeyDeserialize for Hash {
125    type Output = Hash;
126    const KEY_ELEMS: u16 = 1;
127
128    #[inline(always)]
129    fn from_vec(value: Vec<u8>) -> StdResult<Self::Output> {
130        Ok(Hash(value))
131    }
132}
133
134impl KeyDeserialize for &Hash {
135    type Output = Hash;
136    const KEY_ELEMS: u16 = 1;
137
138    #[inline(always)]
139    fn from_vec(value: Vec<u8>) -> StdResult<Self::Output> {
140        Ok(Hash(value))
141    }
142}
143
144impl<'a> Prefixer<'a> for Hash {
145    fn prefix(&self) -> Vec<Key<'_>> {
146        vec![Key::Ref(self.0.as_ref())]
147    }
148}
149
150impl AsRef<[u8]> for Hash {
151    #[inline]
152    fn as_ref(&self) -> &[u8] {
153        self.0.as_ref()
154    }
155}
156
157#[cfg(test)]
158mod tests {
159    use crate::crypto::Hash;
160
161    #[test]
162    fn vec_from_hash() {
163        let h = Hash(vec![1, 2, 3]);
164        let result: Vec<u8> = h.into();
165        assert_eq!(result, vec![1, 2, 3]);
166
167        let h = &Hash(vec![3, 2, 1]);
168        let result: Vec<u8> = h.into();
169        assert_eq!(result, vec![3, 2, 1])
170    }
171}