use p3_challenger::{CanObserve, FieldChallenger, GrindingChallenger};
use p3_commit::Mmcs;
use p3_field::{ExtensionField, Field, TwoAdicField};
pub trait BenchScenario {
type F: Field + TwoAdicField + Ord;
type EF: ExtensionField<Self::F> + TwoAdicField;
type Mmcs: Mmcs<Self::F>;
const FIELD_NAME: &'static str;
const HASH_NAME: &'static str;
fn mmcs() -> Self::Mmcs;
}
pub trait PcsScenario: BenchScenario {
type Challenger: Clone
+ FieldChallenger<Self::F>
+ GrindingChallenger
+ CanObserve<<Self::Mmcs as Mmcs<Self::F>>::Commitment>;
const RATE: usize;
fn challenger() -> Self::Challenger;
}
pub trait PermFromRng: Sized {
fn new_from_rng_128(rng: &mut SmallRng) -> Self;
}
use rand::rngs::SmallRng;
impl PermFromRng for p3_baby_bear::Poseidon2BabyBear<16> {
fn new_from_rng_128(rng: &mut SmallRng) -> Self {
p3_baby_bear::Poseidon2BabyBear::new_from_rng_128(rng)
}
}
impl PermFromRng for p3_baby_bear::Poseidon2BabyBear<24> {
fn new_from_rng_128(rng: &mut SmallRng) -> Self {
p3_baby_bear::Poseidon2BabyBear::new_from_rng_128(rng)
}
}
impl PermFromRng for p3_goldilocks::Poseidon2Goldilocks<8> {
fn new_from_rng_128(rng: &mut SmallRng) -> Self {
p3_goldilocks::Poseidon2Goldilocks::new_from_rng_128(rng)
}
}
impl PermFromRng for p3_goldilocks::Poseidon2Goldilocks<12> {
fn new_from_rng_128(rng: &mut SmallRng) -> Self {
p3_goldilocks::Poseidon2Goldilocks::new_from_rng_128(rng)
}
}
#[macro_export]
macro_rules! impl_poseidon2_config {
(
scenario: $scenario:ident,
field: $field:ty,
ext_degree: $ext_deg:literal,
perm: $perm:ident,
width: $width:literal,
rate: $rate:literal,
digest: $digest:literal,
field_name: $field_name:literal
) => {
use p3_challenger::DuplexChallenger;
use p3_field::{Field, extension::BinomialExtensionField};
use p3_merkle_tree::MerkleTreeMmcs;
use p3_miden_stateful_hasher::StatefulSponge;
use p3_symmetric::{PaddingFreeSponge, TruncatedPermutation};
use rand::{SeedableRng, rngs::SmallRng};
use $crate::{
configs::{BenchScenario, PcsScenario},
fixtures::TEST_SEED,
};
pub const WIDTH: usize = $width;
pub const RATE: usize = $rate;
pub const DIGEST: usize = $digest;
pub type F = $field;
pub type P = <F as Field>::Packing;
pub type EF = BinomialExtensionField<F, $ext_deg>;
pub type Perm = $perm<$width>;
pub type Sponge = StatefulSponge<Perm, WIDTH, RATE, DIGEST>;
pub type MmcsSponge = PaddingFreeSponge<Perm, WIDTH, RATE, DIGEST>;
pub type Compress = TruncatedPermutation<Perm, 2, DIGEST, WIDTH>;
pub type BaseMmcs = MerkleTreeMmcs<P, P, MmcsSponge, Compress, 2, DIGEST>;
pub type Challenger = DuplexChallenger<F, Perm, WIDTH, RATE>;
pub fn create_perm() -> Perm {
let mut rng = SmallRng::seed_from_u64(TEST_SEED);
<Perm as $crate::configs::PermFromRng>::new_from_rng_128(&mut rng)
}
pub fn test_components() -> (Perm, Sponge, Compress) {
let perm = create_perm();
let sponge = Sponge::new(perm.clone());
let compress = Compress::new(perm.clone());
(perm, sponge, compress)
}
pub fn test_challenger() -> Challenger {
Challenger::new(create_perm())
}
#[doc = concat!(stringify!($field), " field with Poseidon2 hash.")]
pub struct $scenario;
impl BenchScenario for $scenario {
type F = F;
type EF = EF;
type Mmcs = BaseMmcs;
const FIELD_NAME: &'static str = $field_name;
const HASH_NAME: &'static str = "poseidon2";
fn mmcs() -> Self::Mmcs {
let perm = create_perm();
Self::Mmcs::new(MmcsSponge::new(perm.clone()), Compress::new(perm), 0)
}
}
impl PcsScenario for $scenario {
type Challenger = Challenger;
const RATE: usize = RATE;
fn challenger() -> Self::Challenger {
test_challenger()
}
}
};
}
#[macro_export]
macro_rules! impl_keccak_config {
(
scenario: $scenario:ident,
field: $field:ty,
ext_degree: $ext_deg:literal,
field_name: $field_name:literal
) => {
use p3_field::{Field, extension::BinomialExtensionField};
use p3_keccak::KeccakF;
use p3_merkle_tree::MerkleTreeMmcs;
use p3_symmetric::{CompressionFunctionFromHasher, PaddingFreeSponge, SerializingHasher};
use $crate::configs::BenchScenario;
pub const WIDTH: usize = 25;
pub const RATE: usize = 17;
pub const DIGEST: usize = 4;
pub type F = $field;
pub type P = <F as Field>::Packing;
pub type EF = BinomialExtensionField<F, $ext_deg>;
pub type KeccakMmcsSponge = PaddingFreeSponge<KeccakF, WIDTH, RATE, DIGEST>;
pub type KeccakCompress = CompressionFunctionFromHasher<KeccakMmcsSponge, 2, DIGEST>;
pub type BaseMmcs =
MerkleTreeMmcs<F, u64, SerializingHasher<KeccakMmcsSponge>, KeccakCompress, 2, DIGEST>;
#[doc = concat!(stringify!($field), " field with Keccak hash.")]
pub struct $scenario;
impl BenchScenario for $scenario {
type F = F;
type EF = EF;
type Mmcs = BaseMmcs;
const FIELD_NAME: &'static str = $field_name;
const HASH_NAME: &'static str = "keccak";
fn mmcs() -> Self::Mmcs {
let inner = KeccakMmcsSponge::new(KeccakF {});
Self::Mmcs::new(
SerializingHasher::new(inner.clone()),
KeccakCompress::new(inner),
0,
)
}
}
};
}
pub mod baby_bear_keccak {
use p3_baby_bear::BabyBear;
crate::impl_keccak_config!(
scenario: BabyBearKeccak,
field: BabyBear,
ext_degree: 4,
field_name: "babybear"
);
}
pub mod baby_bear_poseidon2 {
use p3_baby_bear::{BabyBear, Poseidon2BabyBear};
crate::impl_poseidon2_config!(
scenario: BabyBearPoseidon2,
field: BabyBear,
ext_degree: 4,
perm: Poseidon2BabyBear,
width: 16,
rate: 8,
digest: 8,
field_name: "babybear"
);
}
pub mod goldilocks_keccak {
use p3_goldilocks::Goldilocks;
crate::impl_keccak_config!(
scenario: GoldilocksKeccak,
field: Goldilocks,
ext_degree: 2,
field_name: "goldilocks"
);
}
pub mod goldilocks_poseidon2 {
use p3_goldilocks::{Goldilocks, Poseidon2Goldilocks};
crate::impl_poseidon2_config!(
scenario: GoldilocksPoseidon2,
field: Goldilocks,
ext_degree: 2,
perm: Poseidon2Goldilocks,
width: 12,
rate: 8,
digest: 4,
field_name: "goldilocks"
);
}
pub use baby_bear_keccak::BabyBearKeccak;
pub use baby_bear_poseidon2::BabyBearPoseidon2;
pub use goldilocks_keccak::GoldilocksKeccak;
pub use goldilocks_poseidon2::GoldilocksPoseidon2;