p3_poseidon2/
internal.rs

1//! Inside the Poseidon2 paper, they describe that the internal layers of the hash
2//! function do not require the full properties of MDS matrices.
3//!
4//! > For the partial rounds, the MDS property is not required anymore, and
5//! > we can set up the matrix MI focusing only on providing full diffusion, breaking
6//! > arbitrarily long subspace trails, and ensuring that the polynomial representation
7//! > of the scheme is dense. (Section 5.2)
8//!
9//! This file implements a trait for linear layers that satisfy these three properties.
10
11// The requirements translate to the following 3 properties:
12// 1: All entries are non 0.
13// 2: No Subspace Trails.
14// 3: For a matrix of the form 1 + D, the diagonal D should also be non 0.
15//
16// Properties 1 and 3 are essentially immediate to check and a sufficient condition for property 2
17// is that the minimal polynomial of the matrix M and all its powers M^2, ..., M^{2WIDTH} are maximal and irreducible.
18// This is equivalent to all the characteristic polynomials being irreducible.
19//
20// These can be verified by the following sage code (Changing field/vector/length as desired):
21//
22// field = GF(2^31 - 1);
23// length = 16;
24// vector = [-2,  1,   2,   4,   8,  16,  32,  64, 128, 256, 1024, 4096, 8192, 16384, 32768, 65536];
25// const_mat = matrix.ones(field, length);
26// diag_mat  = diagonal_matrix(field, vector);
27// for i in range(1, 2 * length + 1)
28//      assert ((const_mat + diag_mat)^i).characteristic_polynomial().is_irreducible()
29
30use alloc::vec::Vec;
31
32use p3_field::{Algebra, Field, InjectiveMonomial, PrimeCharacteristicRing};
33
34use crate::add_rc_and_sbox_generic;
35
36/// Initialize an internal layer from a set of constants.
37pub trait InternalLayerConstructor<F>
38where
39    F: Field,
40{
41    /// A constructor which internally will convert the supplied
42    /// constants into the appropriate form for the implementation.
43    fn new_from_constants(internal_constants: Vec<F>) -> Self;
44}
45
46/// Given a vector v compute the matrix vector product (1 + diag(v))state with 1 denoting the constant matrix of ones.
47pub fn matmul_internal<F: Field, A: Algebra<F>, const WIDTH: usize>(
48    state: &mut [A; WIDTH],
49    mat_internal_diag_m_1: [F; WIDTH],
50) {
51    let sum = A::sum_array::<WIDTH>(state);
52    for i in 0..WIDTH {
53        state[i] *= mat_internal_diag_m_1[i];
54        state[i] += sum.clone();
55    }
56}
57
58/// A trait containing all data needed to implement the internal layers of Poseidon2.
59pub trait InternalLayer<R, const WIDTH: usize, const D: u64>: Sync + Clone
60where
61    R: PrimeCharacteristicRing,
62{
63    /// Perform the internal layers of the Poseidon2 permutation on the given state.
64    fn permute_state(&self, state: &mut [R; WIDTH]);
65}
66
67/// A helper method which allows any field to easily implement Internal Layer.
68/// This should only be used in places where performance is not critical.
69#[inline]
70pub fn internal_permute_state<
71    F: Field,
72    A: Algebra<F> + InjectiveMonomial<D>,
73    const WIDTH: usize,
74    const D: u64,
75>(
76    state: &mut [A; WIDTH],
77    diffusion_mat: fn(&mut [A; WIDTH]),
78    internal_constants: &[F],
79) {
80    for elem in internal_constants {
81        add_rc_and_sbox_generic(&mut state[0], *elem);
82        diffusion_mat(state);
83    }
84}