use miden_field::BasedVectorSpace;
use super::{
ARK1, ARK2, AlgebraicSponge, CAPACITY_RANGE, DIGEST_RANGE, Felt, MDS, NUM_ROUNDS, RATE_RANGE,
RATE0_RANGE, RATE1_RANGE, Range, STATE_WIDTH, Word, add_constants,
add_constants_and_apply_ext_round, add_constants_and_apply_inv_sbox,
add_constants_and_apply_sbox, apply_inv_sbox, apply_mds, apply_sbox,
};
#[cfg(test)]
mod tests;
#[allow(rustdoc::private_intra_doc_links)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct Rpx256();
impl AlgebraicSponge for Rpx256 {
#[inline(always)]
fn apply_permutation(state: &mut [Felt; STATE_WIDTH]) {
Self::apply_fb_round(state, 0);
Self::apply_ext_round(state, 1);
Self::apply_fb_round(state, 2);
Self::apply_ext_round(state, 3);
Self::apply_fb_round(state, 4);
Self::apply_ext_round(state, 5);
Self::apply_final_round(state, 6);
}
}
impl Rpx256 {
pub const COLLISION_RESISTANCE: u32 = 128;
pub const STATE_WIDTH: usize = STATE_WIDTH;
pub const RATE_RANGE: Range<usize> = RATE_RANGE;
pub const RATE0_RANGE: Range<usize> = RATE0_RANGE;
pub const RATE1_RANGE: Range<usize> = RATE1_RANGE;
pub const CAPACITY_RANGE: Range<usize> = CAPACITY_RANGE;
pub const DIGEST_RANGE: Range<usize> = DIGEST_RANGE;
pub const MDS: [[Felt; STATE_WIDTH]; STATE_WIDTH] = MDS;
pub const ARK1: [[Felt; STATE_WIDTH]; NUM_ROUNDS] = ARK1;
pub const ARK2: [[Felt; STATE_WIDTH]; NUM_ROUNDS] = ARK2;
#[inline(always)]
pub fn hash(bytes: &[u8]) -> Word {
<Self as AlgebraicSponge>::hash(bytes)
}
#[inline(always)]
pub fn hash_elements<E: BasedVectorSpace<Felt>>(elements: &[E]) -> Word {
<Self as AlgebraicSponge>::hash_elements(elements)
}
#[inline(always)]
pub fn merge(values: &[Word; 2]) -> Word {
<Self as AlgebraicSponge>::merge(values)
}
#[inline(always)]
pub fn merge_many(values: &[Word]) -> Word {
<Self as AlgebraicSponge>::merge_many(values)
}
#[inline(always)]
pub fn merge_in_domain(values: &[Word; 2], domain: Felt) -> Word {
<Self as AlgebraicSponge>::merge_in_domain(values, domain)
}
#[inline(always)]
pub fn hash_elements_in_domain<E: BasedVectorSpace<Felt>>(
elements: &[E],
domain: Felt,
) -> Word {
<Self as AlgebraicSponge>::hash_elements_in_domain(elements, domain)
}
#[inline(always)]
pub fn apply_permutation(state: &mut [Felt; STATE_WIDTH]) {
Self::apply_fb_round(state, 0);
Self::apply_ext_round(state, 1);
Self::apply_fb_round(state, 2);
Self::apply_ext_round(state, 3);
Self::apply_fb_round(state, 4);
Self::apply_ext_round(state, 5);
Self::apply_final_round(state, 6);
}
#[inline(always)]
pub fn apply_fb_round(state: &mut [Felt; STATE_WIDTH], round: usize) {
apply_mds(state);
if !add_constants_and_apply_sbox(state, &ARK1[round]) {
add_constants(state, &ARK1[round]);
apply_sbox(state);
}
apply_mds(state);
if !add_constants_and_apply_inv_sbox(state, &ARK2[round]) {
add_constants(state, &ARK2[round]);
apply_inv_sbox(state);
}
}
#[inline(always)]
pub fn apply_ext_round(state: &mut [Felt; STATE_WIDTH], round: usize) {
if !add_constants_and_apply_ext_round(state, &ARK1[round]) {
Self::apply_ext_round_ref(state, round);
}
}
#[inline(always)]
fn apply_ext_round_ref(state: &mut [Felt; STATE_WIDTH], round: usize) {
add_constants(state, &ARK1[round]);
let [s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11] = *state;
let ext0 = cubic_ext::power7([s0, s1, s2]);
let ext1 = cubic_ext::power7([s3, s4, s5]);
let ext2 = cubic_ext::power7([s6, s7, s8]);
let ext3 = cubic_ext::power7([s9, s10, s11]);
state[0] = ext0[0];
state[1] = ext0[1];
state[2] = ext0[2];
state[3] = ext1[0];
state[4] = ext1[1];
state[5] = ext1[2];
state[6] = ext2[0];
state[7] = ext2[1];
state[8] = ext2[2];
state[9] = ext3[0];
state[10] = ext3[1];
state[11] = ext3[2];
}
#[inline(always)]
pub fn apply_final_round(state: &mut [Felt; STATE_WIDTH], round: usize) {
apply_mds(state);
add_constants(state, &ARK1[round]);
}
}
mod cubic_ext {
use super::Felt;
#[inline(always)]
pub fn mul(a: [Felt; 3], b: [Felt; 3]) -> [Felt; 3] {
let a0b0 = a[0] * b[0];
let a1b1 = a[1] * b[1];
let a2b2 = a[2] * b[2];
let a0b0_a0b1_a1b0_a1b1 = (a[0] + a[1]) * (b[0] + b[1]);
let a0b0_a0b2_a2b0_a2b2 = (a[0] + a[2]) * (b[0] + b[2]);
let a1b1_a1b2_a2b1_a2b2 = (a[1] + a[2]) * (b[1] + b[2]);
let a0b0_minus_a1b1 = a0b0 - a1b1;
let a0b0_a1b2_a2b1 = a1b1_a1b2_a2b1_a2b2 + a0b0_minus_a1b1 - a2b2;
let a0b1_a1b0_a1b2_a2b1_a2b2 =
a0b0_a0b1_a1b0_a1b1 + a1b1_a1b2_a2b1_a2b2 - a1b1.double() - a0b0;
let a0b2_a1b1_a2b0_a2b2 = a0b0_a0b2_a2b0_a2b2 - a0b0_minus_a1b1;
[a0b0_a1b2_a2b1, a0b1_a1b0_a1b2_a2b1_a2b2, a0b2_a1b1_a2b0_a2b2]
}
#[inline(always)]
pub fn square(a: [Felt; 3]) -> [Felt; 3] {
let a0 = a[0];
let a1 = a[1];
let a2 = a[2];
let a2_sq = a2.square();
let a1_a2 = a1 * a2;
let out0 = a0.square() + a1_a2.double();
let out1 = (a0 * a1 + a1_a2).double() + a2_sq;
let out2 = (a0 * a2).double() + a1.square() + a2_sq;
[out0, out1, out2]
}
#[inline(always)]
pub fn power7(a: [Felt; 3]) -> [Felt; 3] {
let a2 = square(a);
let a3 = mul(a2, a);
let a6 = square(a3);
mul(a6, a)
}
}
use p3_challenger::DuplexChallenger;
use p3_symmetric::{
CryptographicPermutation, PaddingFreeSponge, Permutation, TruncatedPermutation,
};
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct RpxPermutation256;
impl RpxPermutation256 {
pub const STATE_WIDTH: usize = STATE_WIDTH;
pub const RATE_RANGE: Range<usize> = Rpx256::RATE_RANGE;
pub const CAPACITY_RANGE: Range<usize> = Rpx256::CAPACITY_RANGE;
pub const DIGEST_RANGE: Range<usize> = Rpx256::DIGEST_RANGE;
#[inline(always)]
pub fn apply_permutation(state: &mut [Felt; STATE_WIDTH]) {
Rpx256::apply_permutation(state);
}
}
impl Permutation<[Felt; STATE_WIDTH]> for RpxPermutation256 {
fn permute_mut(&self, state: &mut [Felt; STATE_WIDTH]) {
Self::apply_permutation(state);
}
}
impl CryptographicPermutation<[Felt; STATE_WIDTH]> for RpxPermutation256 {}
pub type RpxHasher = PaddingFreeSponge<RpxPermutation256, 12, 8, 4>;
pub type RpxCompression = TruncatedPermutation<RpxPermutation256, 2, 4, 12>;
pub type RpxChallenger<F> = DuplexChallenger<F, RpxPermutation256, 12, 8>;