frame_support/
hash.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Hash utilities.
19
20use 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
25// This trait must be kept coherent with frame-support-procedural HasherKind usage
26pub 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
60/// Hasher to use to hash keys to insert to storage.
61pub trait StorageHasher: 'static {
62	const METADATA: metadata_ir::StorageHasherIR;
63	type Output: AsRef<[u8]>;
64	fn hash(x: &[u8]) -> Self::Output;
65
66	/// The max length of the final hash, for the given key type.
67	fn max_len<K: MaxEncodedLen>() -> usize;
68}
69
70/// Hasher to use to hash keys to insert to storage.
71///
72/// Reversible hasher store the encoded key after the hash part.
73pub trait ReversibleStorageHasher: StorageHasher {
74	/// Split the hash part out of the input.
75	///
76	/// I.e. for input `&[hash ++ key ++ some]` returns `&[key ++ some]`
77	fn reverse(x: &[u8]) -> &[u8];
78}
79
80/// Store the key directly.
81pub 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
98/// Hash storage keys with `concat(twox64(key), key)`
99pub 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
120/// Hash storage keys with `concat(blake2_128(key), key)`
121pub 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
142/// Hash storage keys with blake2 128
143pub 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
155/// Hash storage keys with blake2 256
156pub 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
168/// Hash storage keys with twox 128
169pub 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
181/// Hash storage keys with twox 256
182pub 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}