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}