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