1use alloc::vec::Vec;
21use codec::{Codec, MaxEncodedLen};
22use sp_io::hashing::{blake2_128, blake2_256, twox_128, twox_256, twox_64};
23use sp_metadata_ir as metadata_ir;
24
25pub trait Hashable: Sized {
27 fn blake2_128(&self) -> [u8; 16];
28 fn blake2_256(&self) -> [u8; 32];
29 fn blake2_128_concat(&self) -> Vec<u8>;
30 fn twox_128(&self) -> [u8; 16];
31 fn twox_256(&self) -> [u8; 32];
32 fn twox_64_concat(&self) -> Vec<u8>;
33 fn identity(&self) -> Vec<u8>;
34}
35
36impl<T: Codec> Hashable for T {
37 fn blake2_128(&self) -> [u8; 16] {
38 self.using_encoded(blake2_128)
39 }
40 fn blake2_256(&self) -> [u8; 32] {
41 self.using_encoded(blake2_256)
42 }
43 fn blake2_128_concat(&self) -> Vec<u8> {
44 self.using_encoded(Blake2_128Concat::hash)
45 }
46 fn twox_128(&self) -> [u8; 16] {
47 self.using_encoded(twox_128)
48 }
49 fn twox_256(&self) -> [u8; 32] {
50 self.using_encoded(twox_256)
51 }
52 fn twox_64_concat(&self) -> Vec<u8> {
53 self.using_encoded(Twox64Concat::hash)
54 }
55 fn identity(&self) -> Vec<u8> {
56 self.encode()
57 }
58}
59
60pub trait StorageHasher: 'static {
62 const METADATA: metadata_ir::StorageHasherIR;
63 type Output: AsRef<[u8]>;
64 fn hash(x: &[u8]) -> Self::Output;
65
66 fn max_len<K: MaxEncodedLen>() -> usize;
68}
69
70pub trait ReversibleStorageHasher: StorageHasher {
74 fn reverse(x: &[u8]) -> &[u8];
78}
79
80pub struct Identity;
82impl StorageHasher for Identity {
83 const METADATA: metadata_ir::StorageHasherIR = metadata_ir::StorageHasherIR::Identity;
84 type Output = Vec<u8>;
85 fn hash(x: &[u8]) -> Vec<u8> {
86 x.to_vec()
87 }
88 fn max_len<K: MaxEncodedLen>() -> usize {
89 K::max_encoded_len()
90 }
91}
92impl ReversibleStorageHasher for Identity {
93 fn reverse(x: &[u8]) -> &[u8] {
94 x
95 }
96}
97
98pub struct Twox64Concat;
100impl StorageHasher for Twox64Concat {
101 const METADATA: metadata_ir::StorageHasherIR = metadata_ir::StorageHasherIR::Twox64Concat;
102 type Output = Vec<u8>;
103 fn hash(x: &[u8]) -> Vec<u8> {
104 twox_64(x).iter().chain(x.iter()).cloned().collect::<Vec<_>>()
105 }
106 fn max_len<K: MaxEncodedLen>() -> usize {
107 K::max_encoded_len().saturating_add(8)
108 }
109}
110impl ReversibleStorageHasher for Twox64Concat {
111 fn reverse(x: &[u8]) -> &[u8] {
112 if x.len() < 8 {
113 log::error!("Invalid reverse: hash length too short");
114 return &[]
115 }
116 &x[8..]
117 }
118}
119
120pub struct Blake2_128Concat;
122impl StorageHasher for Blake2_128Concat {
123 const METADATA: metadata_ir::StorageHasherIR = metadata_ir::StorageHasherIR::Blake2_128Concat;
124 type Output = Vec<u8>;
125 fn hash(x: &[u8]) -> Vec<u8> {
126 blake2_128(x).iter().chain(x.iter()).cloned().collect::<Vec<_>>()
127 }
128 fn max_len<K: MaxEncodedLen>() -> usize {
129 K::max_encoded_len().saturating_add(16)
130 }
131}
132impl ReversibleStorageHasher for Blake2_128Concat {
133 fn reverse(x: &[u8]) -> &[u8] {
134 if x.len() < 16 {
135 log::error!("Invalid reverse: hash length too short");
136 return &[]
137 }
138 &x[16..]
139 }
140}
141
142pub struct Blake2_128;
144impl StorageHasher for Blake2_128 {
145 const METADATA: metadata_ir::StorageHasherIR = metadata_ir::StorageHasherIR::Blake2_128;
146 type Output = [u8; 16];
147 fn hash(x: &[u8]) -> [u8; 16] {
148 blake2_128(x)
149 }
150 fn max_len<K: MaxEncodedLen>() -> usize {
151 16
152 }
153}
154
155pub struct Blake2_256;
157impl StorageHasher for Blake2_256 {
158 const METADATA: metadata_ir::StorageHasherIR = metadata_ir::StorageHasherIR::Blake2_256;
159 type Output = [u8; 32];
160 fn hash(x: &[u8]) -> [u8; 32] {
161 blake2_256(x)
162 }
163 fn max_len<K: MaxEncodedLen>() -> usize {
164 32
165 }
166}
167
168pub struct Twox128;
170impl StorageHasher for Twox128 {
171 const METADATA: metadata_ir::StorageHasherIR = metadata_ir::StorageHasherIR::Twox128;
172 type Output = [u8; 16];
173 fn hash(x: &[u8]) -> [u8; 16] {
174 twox_128(x)
175 }
176 fn max_len<K: MaxEncodedLen>() -> usize {
177 16
178 }
179}
180
181pub struct Twox256;
183impl StorageHasher for Twox256 {
184 const METADATA: metadata_ir::StorageHasherIR = metadata_ir::StorageHasherIR::Twox256;
185 type Output = [u8; 32];
186 fn hash(x: &[u8]) -> [u8; 32] {
187 twox_256(x)
188 }
189 fn max_len<K: MaxEncodedLen>() -> usize {
190 32
191 }
192}
193
194#[cfg(test)]
195mod tests {
196 use super::*;
197
198 #[test]
199 fn test_twox_64_concat() {
200 let r = Twox64Concat::hash(b"foo");
201 assert_eq!(r.split_at(8), (&twox_128(b"foo")[..8], &b"foo"[..]))
202 }
203
204 #[test]
205 fn test_blake2_128_concat() {
206 let r = Blake2_128Concat::hash(b"foo");
207 assert_eq!(r.split_at(16), (&blake2_128(b"foo")[..], &b"foo"[..]))
208 }
209
210 #[test]
211 fn max_lengths() {
212 use codec::Encode;
213 let encoded_0u32 = &0u32.encode()[..];
214 assert_eq!(Twox64Concat::hash(encoded_0u32).len(), Twox64Concat::max_len::<u32>());
215 assert_eq!(Twox128::hash(encoded_0u32).len(), Twox128::max_len::<u32>());
216 assert_eq!(Twox256::hash(encoded_0u32).len(), Twox256::max_len::<u32>());
217 assert_eq!(Blake2_128::hash(encoded_0u32).len(), Blake2_128::max_len::<u32>());
218 assert_eq!(Blake2_128Concat::hash(encoded_0u32).len(), Blake2_128Concat::max_len::<u32>());
219 assert_eq!(Blake2_256::hash(encoded_0u32).len(), Blake2_256::max_len::<u32>());
220 assert_eq!(Identity::hash(encoded_0u32).len(), Identity::max_len::<u32>());
221 }
222}