jam_std_common/crypto/
hashing.rs1use codec::{Encode, Output};
2use jam_types::Hash;
3use tiny_keccak::{Hasher, Keccak};
4
5pub fn keccak(data: &[u8]) -> Hash {
6 let mut hasher = Keccak::v256();
7 hasher.update(data);
8 let mut output = [0u8; 32];
9 hasher.finalize(&mut output);
10 output
11}
12
13pub fn keccak_concat<I, T>(items: I) -> Hash
15where
16 I: IntoIterator<Item = T>,
17 T: AsRef<[u8]>,
18{
19 let mut hasher = Keccak::v256();
20 for item in items.into_iter() {
21 hasher.update(item.as_ref());
22 }
23 let mut output = [0u8; 32];
24 hasher.finalize(&mut output);
25 output
26}
27
28pub fn hash_raw(data: &[u8]) -> Hash {
29 let mut hasher = Blake2bHasher::new();
30 hasher.update(data);
31 hasher.into_hash()
32}
33
34pub fn hash_raw_concat<I, T>(items: I) -> Hash
36where
37 I: IntoIterator<Item = T>,
38 T: AsRef<[u8]>,
39{
40 let mut hasher = Blake2bHasher::new();
41 for item in items.into_iter() {
42 hasher.update(item.as_ref());
43 }
44 hasher.into_hash()
45}
46
47pub fn hash_encoded(what: &impl Encode) -> Hash {
48 let mut hasher = Blake2bHasher::new();
49 what.encode_to(&mut hasher);
50 hasher.into_hash()
51}
52
53struct Blake2bHasher {
54 state: blake2b_simd::State,
55}
56
57impl Blake2bHasher {
58 fn new() -> Self {
59 let state = blake2b_simd::Params::new().hash_length(32).to_state();
60 Self { state }
61 }
62
63 fn update(&mut self, data: &[u8]) {
64 self.state.update(data);
65 }
66
67 fn into_hash(self) -> Hash {
68 self.state.finalize().as_bytes().try_into().expect("Hash length set to 32")
69 }
70}
71
72impl Output for Blake2bHasher {
73 fn write(&mut self, bytes: &[u8]) {
74 self.update(bytes);
75 }
76}
77
78pub struct HashedInput<'a, I: codec::Input> {
81 inner: &'a mut I,
82 hasher: Blake2bHasher,
83}
84
85impl<'a, I: codec::Input> HashedInput<'a, I> {
86 pub fn new(inner: &'a mut I) -> Self {
88 Self { inner, hasher: Blake2bHasher::new() }
89 }
90
91 pub fn into_hash(self) -> Hash {
93 self.hasher.into_hash()
94 }
95}
96
97impl<I: codec::Input> codec::Input for HashedInput<'_, I> {
98 fn remaining_len(&mut self) -> Result<Option<usize>, codec::Error> {
99 self.inner.remaining_len()
100 }
101
102 fn read(&mut self, buf: &mut [u8]) -> Result<(), codec::Error> {
103 self.inner.read(buf)?;
104 self.hasher.update(buf);
105 Ok(())
106 }
107
108 fn read_byte(&mut self) -> Result<u8, codec::Error> {
109 self.inner.read_byte().inspect(|byte| self.hasher.update(&[*byte]))
110 }
111
112 fn ascend_ref(&mut self) {
113 self.inner.ascend_ref()
114 }
115
116 fn descend_ref(&mut self) -> Result<(), codec::Error> {
117 self.inner.descend_ref()
118 }
119
120 fn on_before_alloc_mem(&mut self, size: usize) -> Result<(), codec::Error> {
121 self.inner.on_before_alloc_mem(size)
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128 use codec::Decode;
129
130 #[derive(Encode, Decode, PartialEq, Eq, Debug)]
131 struct Dummy {
132 x: Vec<Dummy>,
133 y: u8,
134 z: String,
135 }
136
137 #[test]
138 fn hashed_input_works() {
139 let dummy = Dummy {
140 x: vec![Dummy { x: Vec::new(), y: 123, z: "Hello".into() }],
141 y: 133,
142 z: "world".into(),
143 };
144 let bytes = dummy.encode();
145 let expected_hash = hash_raw(&bytes[..]);
146 let mut input = &bytes[..];
147 let mut hashed_input = HashedInput::new(&mut input);
148 let actual = Dummy::decode(&mut hashed_input).unwrap();
149 assert_eq!(dummy, actual);
150 let hash = hashed_input.into_hash();
151 assert_eq!(expected_hash, hash);
152 }
153
154 #[test]
155 fn hash_encoded_works() {
156 let dummy = Dummy {
157 x: vec![Dummy { x: Vec::new(), y: 123, z: "Hello".into() }],
158 y: 133,
159 z: "world".into(),
160 };
161 assert_eq!(hash_raw(&dummy.encode()), hash_encoded(&dummy));
162 assert_eq!(dummy.using_encoded(hash_raw), hash_encoded(&dummy));
163 }
164
165 #[test]
166 fn hash_raw_concat_works() {
167 assert_eq!(
168 hash_raw(&[b"x".as_ref(), b"y", b"z"].concat()),
169 hash_raw_concat([b"x", b"y", b"z"])
170 );
171 }
172
173 #[test]
174 fn keccak_concat_works() {
175 assert_eq!(
176 keccak(&[b"x".as_ref(), b"y", b"z"].concat()),
177 keccak_concat([b"x", b"y", b"z"])
178 );
179 }
180}