poseidon_primitives/poseidon/primitives/
p128pow5t3_compact.rs

1use std::marker::PhantomData;
2
3use ff::PrimeField;
4
5use super::p128pow5t3::P128Pow5T3Constants;
6use super::{Mds, Spec};
7
8/// Poseidon-128 using the $x^5$ S-box, with a width of 3 field elements, and the
9/// standard number of rounds for 128-bit security "with margin".
10///
11#[derive(Debug)]
12pub struct P128Pow5T3Compact<Fp> {
13    _marker: PhantomData<Fp>,
14}
15
16impl<Fp: P128Pow5T3Constants> Spec<Fp, 3, 2> for P128Pow5T3Compact<Fp> {
17    fn full_rounds() -> usize {
18        8
19    }
20
21    fn partial_rounds() -> usize {
22        Fp::partial_rounds()
23    }
24
25    fn sbox(val: Fp) -> Fp {
26        val.pow_vartime([5])
27    }
28
29    fn secure_mds() -> usize {
30        unimplemented!()
31    }
32
33    fn constants() -> (Vec<[Fp; 3]>, Mds<Fp, 3>, Mds<Fp, 3>) {
34        let (mut rc, mds, inv) = (Fp::round_constants(), Fp::mds(), Fp::mds_inv());
35
36        let first_partial = Self::full_rounds() / 2;
37        let after_partials = first_partial + Self::partial_rounds();
38
39        // Propagate the constants of each partial round into the next.
40        for i in first_partial..after_partials {
41            // Extract the constants rc[i][1] and rc[i][2] that do not pass through the S-box.
42            // Leave the value 0 in their place.
43            // rc[i][0] stays in place.
44            let rc_tail = vec_remove_tail(&mut rc[i]);
45
46            // Pass forward through the MDS matrix.
47            let rc_carry = mat_mul(&mds, &rc_tail);
48
49            // Accumulate the carried constants into the next round.
50            vec_accumulate(&mut rc[i + 1], &rc_carry);
51        }
52        // Now constants have accumulated into the next full round.
53
54        (rc, mds, inv)
55    }
56}
57
58fn mat_mul<Fp: PrimeField, const T: usize>(mat: &Mds<Fp, T>, input: &[Fp; T]) -> [Fp; T] {
59    let mut out = [Fp::ZERO; T];
60    #[allow(clippy::needless_range_loop)]
61    for i in 0..T {
62        for j in 0..T {
63            out[i] += mat[i][j] * input[j];
64        }
65    }
66    out
67}
68
69fn vec_accumulate<Fp: PrimeField, const T: usize>(a: &mut [Fp; T], b: &[Fp; T]) {
70    for i in 0..T {
71        a[i] += b[i];
72    }
73}
74
75fn vec_remove_tail<Fp: PrimeField, const T: usize>(a: &mut [Fp; T]) -> [Fp; T] {
76    let mut tail = [Fp::ZERO; T];
77    for i in 1..T {
78        tail[i] = a[i];
79        a[i] = Fp::ZERO;
80    }
81    tail
82}