1#![cfg_attr(not(feature = "std"), no_std)]
2
3extern crate alloc;
4
5use alloc::vec::Vec;
6
7use codec::{Decode, Encode};
8use core::{
9 clone::Clone,
10 cmp::{Eq, PartialEq},
11 convert::TryInto,
12 default::Default,
13 fmt::Debug,
14 iter::Extend,
15 prelude::rust_2024::derive,
16};
17
18use p3_field::PrimeCharacteristicRing;
19use p3_goldilocks::Goldilocks;
20use qp_poseidon_core::{
21 hash_for_circuit, hash_to_bytes,
22 serialization::{bytes_to_digest, u128_to_quantized_felt, u64_to_felts},
23 PROOF_NODE_MAX_SIZE_FELTS,
24};
25use scale_info::TypeInfo;
26use sp_core::{Hasher, H256};
27use sp_storage::StateVersion;
28use sp_trie::{LayoutV0, LayoutV1, TrieConfiguration};
29
30pub trait ToFelts {
36 fn write_felts(&self, dest: &mut Vec<Goldilocks>);
38
39 fn to_felts(&self) -> Vec<Goldilocks> {
41 let mut vec = Vec::new();
42 self.write_felts(&mut vec);
43 vec
44 }
45}
46
47impl ToFelts for u32 {
52 fn write_felts(&self, dest: &mut Vec<Goldilocks>) {
53 dest.push(Goldilocks::from_u32(*self));
54 }
55}
56
57impl ToFelts for u64 {
58 fn write_felts(&self, dest: &mut Vec<Goldilocks>) {
59 dest.extend(u64_to_felts(*self));
60 }
61}
62
63impl ToFelts for u128 {
66 fn write_felts(&self, dest: &mut Vec<Goldilocks>) {
67 dest.push(u128_to_quantized_felt(*self));
68 }
69}
70
71impl ToFelts for [u8; 32] {
76 fn write_felts(&self, dest: &mut Vec<Goldilocks>) {
77 dest.extend(bytes_to_digest::<Goldilocks>(self));
78 }
79}
80
81impl ToFelts for sp_core::crypto::AccountId32 {
85 fn write_felts(&self, dest: &mut Vec<Goldilocks>) {
86 let bytes: &[u8; 32] = self.as_ref();
87 dest.extend(bytes_to_digest::<Goldilocks>(bytes));
88 }
89}
90
91impl<T: ToFelts> ToFelts for Option<T> {
92 fn write_felts(&self, dest: &mut Vec<Goldilocks>) {
93 match self {
94 Some(v) => {
95 dest.push(Goldilocks::ONE);
96 v.write_felts(dest);
97 },
98 None => {
99 dest.push(Goldilocks::ZERO);
100 },
101 }
102 }
103}
104
105impl<T: ToFelts> ToFelts for Vec<T> {
106 fn write_felts(&self, dest: &mut Vec<Goldilocks>) {
107 dest.push(Goldilocks::from_u32(self.len() as u32));
109 for item in self {
110 item.write_felts(dest);
111 }
112 }
113}
114
115macro_rules! impl_to_felts_tuple {
117 ($($name:ident)+) => {
118 impl<$($name: ToFelts),+> ToFelts for ($($name,)+) {
119 fn write_felts(&self, dest: &mut Vec<Goldilocks>) {
120 #[allow(non_snake_case)]
121 let ($($name,)+) = self;
122 $($name.write_felts(dest);)+
123 }
124 }
125 }
126}
127
128impl_to_felts_tuple!(A);
129impl_to_felts_tuple!(A B);
130impl_to_felts_tuple!(A B C);
131impl_to_felts_tuple!(A B C D);
132impl_to_felts_tuple!(A B C D E);
133impl_to_felts_tuple!(A B C D E F);
134
135#[cfg(feature = "serde")]
136use serde::{Deserialize, Serialize};
137
138#[derive(Default)]
140pub struct PoseidonStdHasher(Vec<u8>);
141
142impl core::hash::Hasher for PoseidonStdHasher {
143 fn finish(&self) -> u64 {
144 let hash = PoseidonHasher::hash_for_circuit(self.0.as_slice());
145 u64::from_le_bytes(hash[0..8].try_into().unwrap())
146 }
147
148 fn write(&mut self, bytes: &[u8]) {
149 self.0.extend_from_slice(bytes)
150 }
151}
152
153#[derive(PartialEq, Eq, Clone, Debug, Encode, Decode, TypeInfo)]
155#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
156pub struct PoseidonHasher;
157
158impl Hasher for PoseidonHasher {
159 type Out = H256;
160 type StdHasher = PoseidonStdHasher;
161 const LENGTH: usize = 32;
162
163 fn hash(x: &[u8]) -> H256 {
164 H256::from_slice(&Self::hash_for_circuit(x))
165 }
166}
167
168impl PoseidonHasher {
169 pub fn hash_for_circuit(x: &[u8]) -> [u8; 32] {
174 hash_for_circuit::<PROOF_NODE_MAX_SIZE_FELTS>(x)
175 }
176
177 pub fn hash_storage<T: Decode + ToFelts>(x: &[u8]) -> [u8; 32] {
182 let t = T::decode(&mut &x[..])
183 .expect("Input bytes length or format mismatch for the expected type");
184
185 let felts = t.to_felts();
186 hash_to_bytes(&felts)
187 }
188}
189
190impl sp_runtime::traits::Hash for PoseidonHasher {
191 type Output = H256;
192
193 fn hash(s: &[u8]) -> Self::Output {
194 H256::from_slice(&Self::hash_for_circuit(s))
195 }
196
197 fn hash_of<S: Encode>(s: &S) -> Self::Output {
199 Encode::using_encoded(s, <Self as Hasher>::hash)
200 }
201
202 fn ordered_trie_root(input: Vec<Vec<u8>>, state_version: StateVersion) -> Self::Output {
203 log::debug!(target: "poseidon",
204 "PoseidonHasher::ordered_trie_root input={input:?} version={state_version:?}",
205 );
206 let res = match state_version {
207 StateVersion::V0 => LayoutV0::<PoseidonHasher>::ordered_trie_root(input),
208 StateVersion::V1 => LayoutV1::<PoseidonHasher>::ordered_trie_root(input),
209 };
210 log::debug!(target: "poseidon", "PoseidonHasher::ordered_trie_root res={res:?}");
211 res
212 }
213
214 fn trie_root(input: Vec<(Vec<u8>, Vec<u8>)>, version: StateVersion) -> Self::Output {
215 log::debug!(target: "poseidon",
216 "PoseidonHasher::trie_root input={input:?} version={version:?}"
217 );
218 let res = match version {
219 StateVersion::V0 => LayoutV0::<PoseidonHasher>::trie_root(input),
220 StateVersion::V1 => LayoutV1::<PoseidonHasher>::trie_root(input),
221 };
222 log::debug!(target: "poseidon", "PoseidonHasher::trie_root res={res:?}");
223 res
224 }
225}
226
227#[cfg(test)]
228mod tests {
229 use super::*;
230 use hex;
231 use qp_poseidon_constants::POSEIDON2_OUTPUT;
232 use qp_poseidon_core::serialization::bytes_to_felts;
233 use scale_info::prelude::vec;
234
235 #[cfg(feature = "std")]
236 use env_logger;
237
238 #[cfg(all(feature = "std", test))]
239 #[ctor::ctor]
240 fn init_logger_global() {
241 let _ = env_logger::builder().is_test(true).try_init();
242 }
243
244 #[test]
245 fn test_substrate_wrapper_compatibility() {
246 let input = b"test data";
247 let core_hash = hash_for_circuit::<PROOF_NODE_MAX_SIZE_FELTS>(input);
248 let wrapper_hash = PoseidonHasher::hash_for_circuit(input);
249 assert_eq!(core_hash, wrapper_hash);
250 }
251
252 #[test]
253 fn test_empty_input() {
254 let result = PoseidonHasher::hash_for_circuit(&[]);
255 assert_eq!(result.len(), 32);
256 }
257
258 #[test]
259 fn test_single_byte() {
260 let input = vec![42u8];
261 let result = PoseidonHasher::hash_for_circuit(&input);
262 assert_eq!(result.len(), 32);
263 }
264
265 #[test]
266 fn test_exactly_32_bytes() {
267 let input = [1u8; 32];
268 let result = PoseidonHasher::hash_for_circuit(&input);
269 assert_eq!(result.len(), 32);
270 }
271
272 #[test]
273 fn test_multiple_chunks() {
274 let input = [2u8; 64];
275 let result = PoseidonHasher::hash_for_circuit(&input);
276 assert_eq!(result.len(), 32);
277 }
278
279 #[test]
280 fn test_partial_chunk() {
281 let input = [3u8; 40];
282 let result = PoseidonHasher::hash_for_circuit(&input);
283 assert_eq!(result.len(), 32);
284 }
285
286 #[test]
287 fn test_consistency() {
288 let input = [4u8; 50];
289 let iterations = 100;
290 let current_hash = PoseidonHasher::hash_for_circuit(&input);
291
292 for _ in 0..iterations {
293 let hash1 = PoseidonHasher::hash_for_circuit((¤t_hash).as_ref());
294 let current_hash = PoseidonHasher::hash_for_circuit((¤t_hash).as_ref());
295 assert_eq!(hash1, current_hash, "Hash function should be deterministic");
296 }
297 }
298
299 #[test]
300 fn test_different_inputs() {
301 let input1 = [5u8; 32];
302 let input2 = [6u8; 32];
303 let hash1 = PoseidonHasher::hash_for_circuit(&input1);
304 let hash2 = PoseidonHasher::hash_for_circuit(&input2);
305 assert_ne!(hash1, hash2, "Different inputs should produce different hashes");
306 }
307
308 #[test]
309 fn test_poseidon_hash_input_sizes() {
310 for size in 1..=128 {
311 let input: Vec<u8> = (0..size).map(|i| (i * i % 256) as u8).collect();
312 let hash = PoseidonHasher::hash_for_circuit(&input);
313 assert_eq!(
314 hash.as_slice().len(),
315 32,
316 "Input size {} should produce 32-byte hash",
317 size
318 );
319 }
320 }
321
322 #[test]
323 fn test_big_preimage() {
324 for overflow in 1..=200 {
325 let preimage = (18446744069414584321u64 + overflow).to_le_bytes();
326 let _hash = PoseidonHasher::hash_for_circuit(&preimage);
327 }
328 }
329
330 #[test]
331 fn test_circuit_preimage() {
332 let preimage =
333 hex::decode("afd8e7530b95ee5ebab950c9a0c62fae1e80463687b3982233028e914f8ec7cc");
334 let hash = PoseidonHasher::hash_for_circuit(&*preimage.unwrap());
335 let _hash = PoseidonHasher::hash_for_circuit(hash.as_slice());
336 }
337
338 #[test]
339 fn test_random_inputs() {
340 let hex_strings = [
341 "a3f8",
342 "1b7e9d",
343 "4c2a6f81",
344 "e5d30b9a",
345 "1a4f7c2e9b0d8356",
346 "3e8d2a7f5c1b09e4d6f7a2c8",
347 "7b3e9a1f4c8d2e6b0a5f9d3c",
348 "1a4f7c2e9b0d83561a4f7c2e9b0d83561a4f7c2e9b0d83561a4f7c2e9b0d8356",
349 "e5d30b9a4c2a6f81e5d30b9a4c2a6f81e5d30b9a4c2a6f81e5d30b9a4c2a6f81",
350 ];
351
352 for hex_string in hex_strings.iter() {
353 let preimage = hex::decode(hex_string).unwrap();
354 let hash = PoseidonHasher::hash_for_circuit(&preimage);
355 let _hash2 = PoseidonHasher::hash_for_circuit(&hash.as_slice());
356 }
357 }
358
359 #[test]
360 fn test_substrate_hash_512() {
361 use qp_poseidon_core::{hash_bytes, hash_squeeze_twice};
362
363 let input = b"test substrate 512-bit";
364 let hash512 = hash_squeeze_twice(input);
365
366 assert_eq!(hash512.len(), 64);
368
369 let hash512_2 = hash_squeeze_twice(input);
371 assert_eq!(hash512, hash512_2);
372
373 let regular_hash = hash_bytes(input);
375 assert_eq!(&hash512[0..32], ®ular_hash);
376 }
377
378 #[test]
379 fn test_hash_twice() {
380 use qp_poseidon_core::hash_twice;
381
382 let preimage =
383 hex::decode("afd8e7530b95ee5ebab950c9a0c62fae1e80463687b3982233028e914f8ec7cc")
384 .unwrap();
385 let felts = bytes_to_felts(&preimage);
386 let _hash = hash_twice(&felts);
387 }
388
389 #[test]
390 fn test_hash_storage() {
391 use sp_core::crypto::AccountId32;
392
393 let asset_id = 42_u32;
394 let transfer_count = 7_u64;
395 let from_account = AccountId32::new([1u8; 32]);
396 let to_account = AccountId32::new([2u8; 32]);
397 let amount = 1_000_000_u128;
398
399 let encoded =
400 (asset_id, transfer_count, from_account.clone(), to_account.clone(), amount).encode();
401
402 type TransferKey = (u32, u64, AccountId32, AccountId32, u128);
404
405 let hash = PoseidonHasher::hash_storage::<TransferKey>(&encoded);
406 assert_eq!(hash.len(), 32);
407
408 let invalid_encoded = &encoded[0..encoded.len() - 1];
410
411 let result = std::panic::catch_unwind(|| {
412 let _ = PoseidonHasher::hash_storage::<TransferKey>(invalid_encoded);
413 });
414 assert!(result.is_err(), "Expected panic due to invalid input length");
415 }
416
417 #[test]
418 fn test_hash_storage_generic() {
419 let val = 12345_u64;
421 let encoded = val.encode();
422 let hash = PoseidonHasher::hash_storage::<u64>(&encoded);
423 assert_eq!(hash.len(), 32);
424
425 let val_tuple = (1u32, 2u64);
427 let encoded_tuple = val_tuple.encode();
428 let hash_tuple = PoseidonHasher::hash_storage::<(u32, u64)>(&encoded_tuple);
429 assert_eq!(hash_tuple.len(), 32);
430
431 let val_u32 = 12345_u32;
433 let encoded_u32 = val_u32.encode();
434 let hash_u32 = PoseidonHasher::hash_storage::<u32>(&encoded_u32);
435 assert_eq!(hash_u32.len(), 32);
436
437 let val_vec = vec![1u32, 2u32, 3u32];
439 let encoded_vec = val_vec.encode();
440 let hash_vec = PoseidonHasher::hash_storage::<Vec<u32>>(&encoded_vec);
441 assert_eq!(hash_vec.len(), 32);
442 }
443
444 #[test]
445 fn test_to_felts_uses_4_felts_for_accounts() {
446 use sp_core::crypto::AccountId32;
447
448 let account = AccountId32::new([42u8; 32]);
449 let felts = account.to_felts();
450
451 assert_eq!(felts.len(), POSEIDON2_OUTPUT);
453 }
454
455 #[test]
456 fn test_to_felts_uses_4_felts_for_byte_arrays() {
457 let bytes = [42u8; 32];
458 let felts = bytes.to_felts();
459
460 assert_eq!(felts.len(), POSEIDON2_OUTPUT);
462 }
463}