p3_symmetric/
sponge.rs
1use alloc::string::String;
2use core::marker::PhantomData;
3
4use itertools::Itertools;
5use p3_field::{reduce_32, Field, PrimeField, PrimeField32};
6
7use crate::hasher::CryptographicHasher;
8use crate::permutation::CryptographicPermutation;
9
10#[derive(Copy, Clone, Debug)]
14pub struct PaddingFreeSponge<P, const WIDTH: usize, const RATE: usize, const OUT: usize> {
15 permutation: P,
16}
17
18impl<P, const WIDTH: usize, const RATE: usize, const OUT: usize>
19 PaddingFreeSponge<P, WIDTH, RATE, OUT>
20{
21 pub const fn new(permutation: P) -> Self {
22 Self { permutation }
23 }
24}
25
26impl<T, P, const WIDTH: usize, const RATE: usize, const OUT: usize> CryptographicHasher<T, [T; OUT]>
27 for PaddingFreeSponge<P, WIDTH, RATE, OUT>
28where
29 T: Default + Copy,
30 P: CryptographicPermutation<[T; WIDTH]>,
31{
32 fn hash_iter<I>(&self, input: I) -> [T; OUT]
33 where
34 I: IntoIterator<Item = T>,
35 {
36 let mut state = [T::default(); WIDTH];
38 let mut input = input.into_iter();
39
40 'outer: loop {
43 for i in 0..RATE {
44 if let Some(x) = input.next() {
45 state[i] = x;
46 } else {
47 if i != 0 {
48 self.permutation.permute_mut(&mut state);
49 }
50 break 'outer;
51 }
52 }
53 self.permutation.permute_mut(&mut state);
54 }
55
56 state[..OUT].try_into().unwrap()
57 }
58}
59
60#[derive(Clone, Debug)]
65pub struct MultiField32PaddingFreeSponge<
66 F,
67 PF,
68 P,
69 const WIDTH: usize,
70 const RATE: usize,
71 const OUT: usize,
72> {
73 permutation: P,
74 num_f_elms: usize,
75 _phantom: PhantomData<(F, PF)>,
76}
77
78impl<F, PF, P, const WIDTH: usize, const RATE: usize, const OUT: usize>
79 MultiField32PaddingFreeSponge<F, PF, P, WIDTH, RATE, OUT>
80where
81 F: PrimeField32,
82 PF: Field,
83{
84 pub fn new(permutation: P) -> Result<Self, String> {
85 if F::order() >= PF::order() {
86 return Err(String::from("F::order() must be less than PF::order()"));
87 }
88
89 let num_f_elms = PF::bits() / F::bits();
90 Ok(Self {
91 permutation,
92 num_f_elms,
93 _phantom: PhantomData,
94 })
95 }
96}
97
98impl<F, PF, P, const WIDTH: usize, const RATE: usize, const OUT: usize>
99 CryptographicHasher<F, [PF; OUT]> for MultiField32PaddingFreeSponge<F, PF, P, WIDTH, RATE, OUT>
100where
101 F: PrimeField32,
102 PF: PrimeField + Default + Copy,
103 P: CryptographicPermutation<[PF; WIDTH]>,
104{
105 fn hash_iter<I>(&self, input: I) -> [PF; OUT]
106 where
107 I: IntoIterator<Item = F>,
108 {
109 let mut state = [PF::default(); WIDTH];
110 for block_chunk in &input.into_iter().chunks(RATE) {
111 for (chunk_id, chunk) in (&block_chunk.chunks(self.num_f_elms))
112 .into_iter()
113 .enumerate()
114 {
115 state[chunk_id] = reduce_32(&chunk.collect_vec());
116 }
117 state = self.permutation.permute(state);
118 }
119
120 state[..OUT].try_into().unwrap()
121 }
122}