use core::marker::PhantomData;
use core::ops::Mul;
use p3_field::AbstractField;
use p3_poseidon2::{
add_rc_and_sbox_generic, external_initial_permute_state, external_terminal_permute_state,
ExternalLayer, GenericPoseidon2LinearLayers, InternalLayer, MDSMat4,
};
use crate::{
FieldParameters, MontyField31, MontyParameters, Poseidon2ExternalLayerMonty31,
Poseidon2InternalLayerMonty31,
};
pub trait InternalLayerBaseParameters<MP: MontyParameters, const WIDTH: usize>:
Clone + Sync
{
type ArrayLike: AsRef<[MontyField31<MP>]> + Sized;
const INTERNAL_DIAG_MONTY: [MontyField31<MP>; WIDTH];
fn internal_layer_mat_mul(state: &mut [MontyField31<MP>; WIDTH], sum: MontyField31<MP>);
fn generic_internal_linear_layer<AF: AbstractField + Mul<MontyField31<MP>, Output = AF>>(
state: &mut [AF; WIDTH],
);
}
#[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
pub trait InternalLayerParameters<FP: FieldParameters, const WIDTH: usize>:
InternalLayerBaseParameters<FP, WIDTH>
{
}
#[cfg(all(
target_arch = "x86_64",
target_feature = "avx2",
not(all(feature = "nightly-features", target_feature = "avx512f"))
))]
pub trait InternalLayerParameters<FP: FieldParameters, const WIDTH: usize>:
InternalLayerBaseParameters<FP, WIDTH> + crate::InternalLayerParametersAVX2<FP, WIDTH>
{
}
#[cfg(all(
feature = "nightly-features",
target_arch = "x86_64",
target_feature = "avx512f"
))]
pub trait InternalLayerParameters<FP: FieldParameters, const WIDTH: usize>:
InternalLayerBaseParameters<FP, WIDTH> + crate::InternalLayerParametersAVX512<FP, WIDTH>
{
}
#[cfg(not(any(
all(target_arch = "aarch64", target_feature = "neon"),
all(
target_arch = "x86_64",
target_feature = "avx2",
not(all(feature = "nightly-features", target_feature = "avx512f"))
),
all(
feature = "nightly-features",
target_arch = "x86_64",
target_feature = "avx512f"
),
)))]
pub trait InternalLayerParameters<FP: FieldParameters, const WIDTH: usize>:
InternalLayerBaseParameters<FP, WIDTH>
{
}
impl<FP, const WIDTH: usize, P2P, const D: u64> InternalLayer<MontyField31<FP>, WIDTH, D>
for Poseidon2InternalLayerMonty31<FP, WIDTH, P2P>
where
FP: FieldParameters,
P2P: InternalLayerParameters<FP, WIDTH>,
{
fn permute_state(&self, state: &mut [MontyField31<FP>; WIDTH]) {
self.internal_constants.iter().for_each(|rc| {
state[0] += *rc;
state[0] = state[0].exp_const_u64::<D>();
let part_sum: MontyField31<FP> = state[1..].iter().cloned().sum();
let full_sum = part_sum + state[0];
state[0] = part_sum - state[0];
P2P::internal_layer_mat_mul(state, full_sum);
})
}
}
impl<FP, const WIDTH: usize, const D: u64> ExternalLayer<MontyField31<FP>, WIDTH, D>
for Poseidon2ExternalLayerMonty31<FP, WIDTH>
where
FP: FieldParameters,
{
fn permute_state_initial(&self, state: &mut [MontyField31<FP>; WIDTH]) {
external_initial_permute_state(
state,
self.external_constants.get_initial_constants(),
add_rc_and_sbox_generic::<_, D>,
&MDSMat4,
);
}
fn permute_state_terminal(&self, state: &mut [MontyField31<FP>; WIDTH]) {
external_terminal_permute_state(
state,
self.external_constants.get_terminal_constants(),
add_rc_and_sbox_generic::<_, D>,
&MDSMat4,
);
}
}
pub struct GenericPoseidon2LinearLayersMonty31<FP, ILBP> {
_phantom1: PhantomData<FP>,
_phantom2: PhantomData<ILBP>,
}
impl<FP, AF, ILBP, const WIDTH: usize> GenericPoseidon2LinearLayers<AF, WIDTH>
for GenericPoseidon2LinearLayersMonty31<FP, ILBP>
where
FP: FieldParameters,
AF: AbstractField + Mul<MontyField31<FP>, Output = AF>,
ILBP: InternalLayerBaseParameters<FP, WIDTH>,
{
fn internal_linear_layer(state: &mut [AF; WIDTH]) {
ILBP::generic_internal_linear_layer(state);
}
}