Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use 24-element Poseidon2 for leaf hashing #754

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion core/src/stark/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ pub struct ShardOpenedValues<T: Serialize> {
/// The maximum number of elements that can be stored in the public values vec. Both SP1 and recursive
/// proofs need to pad their public_values vec to this length. This is required since the recursion
/// verification program expects the public values vec to be fixed length.
pub const PROOF_MAX_NUM_PVS: usize = 232;
///
/// nhuck@ : I had to increase this to match 24-wide Poseidon2 states.
pub const PROOF_MAX_NUM_PVS: usize = 232 + 72;

#[derive(Serialize, Deserialize, Clone)]
#[serde(bound = "")]
Expand Down
25 changes: 17 additions & 8 deletions core/src/utils/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,21 @@ use p3_symmetric::Hash;
use p3_symmetric::{PaddingFreeSponge, TruncatedPermutation};
use serde::Deserialize;
use serde::Serialize;
use sp1_primitives::poseidon2_init;
use sp1_primitives::{poseidon2_16_init, poseidon2_24_init};

pub const DIGEST_SIZE: usize = 8;

/// A configuration for inner recursion.
pub type InnerVal = BabyBear;
pub type InnerChallenge = BinomialExtensionField<InnerVal, 4>;
pub type InnerPerm =
Poseidon2<InnerVal, Poseidon2ExternalMatrixGeneral, DiffusionMatrixBabyBear, 24, 7>;
pub type InnerPerm16 =
Poseidon2<InnerVal, Poseidon2ExternalMatrixGeneral, DiffusionMatrixBabyBear, 16, 7>;
pub type InnerHash = PaddingFreeSponge<InnerPerm, 16, 8, 8>;
pub type InnerHash = PaddingFreeSponge<InnerPerm, 24, 16, 8>;
pub type InnerDigestHash = Hash<InnerVal, InnerVal, DIGEST_SIZE>;
pub type InnerDigest = [InnerVal; DIGEST_SIZE];
pub type InnerCompress = TruncatedPermutation<InnerPerm, 2, 8, 16>;
pub type InnerCompress = TruncatedPermutation<InnerPerm16, 2, 8, 16>;
pub type InnerValMmcs = FieldMerkleTreeMmcs<
<InnerVal as Field>::Packing,
<InnerVal as Field>::Packing,
Expand All @@ -36,7 +38,7 @@ pub type InnerValMmcs = FieldMerkleTreeMmcs<
8,
>;
pub type InnerChallengeMmcs = ExtensionMmcs<InnerVal, InnerChallenge, InnerValMmcs>;
pub type InnerChallenger = DuplexChallenger<InnerVal, InnerPerm, 16>;
pub type InnerChallenger = DuplexChallenger<InnerVal, InnerPerm, 24>;
pub type InnerDft = Radix2DitParallel;
pub type InnerPcs = TwoAdicFriPcs<InnerVal, InnerDft, InnerValMmcs, InnerChallengeMmcs>;
pub type InnerQueryProof = QueryProof<InnerChallenge, InnerChallengeMmcs>;
Expand All @@ -48,14 +50,19 @@ pub type InnerPcsProof =

/// The permutation for inner recursion.
pub fn inner_perm() -> InnerPerm {
poseidon2_init()
poseidon2_24_init()
}

pub fn inner_perm16() -> InnerPerm16 {
poseidon2_16_init()
}

/// The FRI config for sp1 proofs.
pub fn sp1_fri_config() -> FriConfig<InnerChallengeMmcs> {
let perm = inner_perm();
let perm16 = inner_perm16();
let hash = InnerHash::new(perm.clone());
let compress = InnerCompress::new(perm.clone());
let compress = InnerCompress::new(perm16.clone());
let challenge_mmcs = InnerChallengeMmcs::new(InnerValMmcs::new(hash, compress));
let num_queries = match std::env::var("FRI_QUERIES") {
Ok(value) => value.parse().unwrap(),
Expand All @@ -72,8 +79,9 @@ pub fn sp1_fri_config() -> FriConfig<InnerChallengeMmcs> {
/// The FRI config for inner recursion.
pub fn inner_fri_config() -> FriConfig<InnerChallengeMmcs> {
let perm = inner_perm();
let perm16 = inner_perm16();
let hash = InnerHash::new(perm.clone());
let compress = InnerCompress::new(perm.clone());
let compress = InnerCompress::new(perm16.clone());
let challenge_mmcs = InnerChallengeMmcs::new(InnerValMmcs::new(hash, compress));
let num_queries = match std::env::var("FRI_QUERIES") {
Ok(value) => value.parse().unwrap(),
Expand Down Expand Up @@ -119,8 +127,9 @@ impl From<std::marker::PhantomData<BabyBearPoseidon2Inner>> for BabyBearPoseidon
impl BabyBearPoseidon2Inner {
pub fn new() -> Self {
let perm = inner_perm();
let perm16 = inner_perm16();
let hash = InnerHash::new(perm.clone());
let compress = InnerCompress::new(perm.clone());
let compress = InnerCompress::new(perm16.clone());
let val_mmcs = InnerValMmcs::new(hash, compress);
let dft = InnerDft {};
let fri_config = inner_fri_config();
Expand Down
47 changes: 37 additions & 10 deletions core/src/utils/prove.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,16 +403,17 @@ pub mod baby_bear_poseidon2 {
use p3_poseidon2::Poseidon2ExternalMatrixGeneral;
use p3_symmetric::{PaddingFreeSponge, TruncatedPermutation};
use serde::{Deserialize, Serialize};
use sp1_primitives::RC_16_30;
use sp1_primitives::{RC_24_29, RC_16_30};

use crate::stark::StarkGenericConfig;

pub type Val = BabyBear;
pub type Challenge = BinomialExtensionField<Val, 4>;

pub type Perm = Poseidon2<Val, Poseidon2ExternalMatrixGeneral, DiffusionMatrixBabyBear, 16, 7>;
pub type MyHash = PaddingFreeSponge<Perm, 16, 8, 8>;
pub type MyCompress = TruncatedPermutation<Perm, 2, 8, 16>;
pub type Perm = Poseidon2<Val, Poseidon2ExternalMatrixGeneral, DiffusionMatrixBabyBear, 24, 7>;
pub type Perm16 = Poseidon2<Val, Poseidon2ExternalMatrixGeneral, DiffusionMatrixBabyBear, 16, 7>;
pub type MyHash = PaddingFreeSponge<Perm, 24, 16, 8>;
pub type MyCompress = TruncatedPermutation<Perm16, 2, 8, 16>;
pub type ValMmcs = FieldMerkleTreeMmcs<
<Val as Field>::Packing,
<Val as Field>::Packing,
Expand All @@ -422,10 +423,31 @@ pub mod baby_bear_poseidon2 {
>;
pub type ChallengeMmcs = ExtensionMmcs<Val, Challenge, ValMmcs>;
pub type Dft = Radix2DitParallel;
pub type Challenger = DuplexChallenger<Val, Perm, 16>;
pub type Challenger = DuplexChallenger<Val, Perm, 24>;
type Pcs = TwoAdicFriPcs<Val, Dft, ValMmcs, ChallengeMmcs>;

pub fn my_perm() -> Perm {
const ROUNDS_F: usize = 8;
const ROUNDS_P: usize = 21;
let mut round_constants = RC_24_29.to_vec();
let internal_start = ROUNDS_F / 2;
let internal_end = (ROUNDS_F / 2) + ROUNDS_P;
let internal_round_constants = round_constants
.drain(internal_start..internal_end)
.map(|vec| vec[0])
.collect::<Vec<_>>();
let external_round_constants = round_constants;
Perm::new(
ROUNDS_F,
external_round_constants,
Poseidon2ExternalMatrixGeneral,
ROUNDS_P,
internal_round_constants,
DiffusionMatrixBabyBear,
)
}

pub fn my_perm16() -> Perm16 {
const ROUNDS_F: usize = 8;
const ROUNDS_P: usize = 13;
let mut round_constants = RC_16_30.to_vec();
Expand All @@ -436,7 +458,7 @@ pub mod baby_bear_poseidon2 {
.map(|vec| vec[0])
.collect::<Vec<_>>();
let external_round_constants = round_constants;
Perm::new(
Perm16::new(
ROUNDS_F,
external_round_constants,
Poseidon2ExternalMatrixGeneral,
Expand All @@ -446,10 +468,12 @@ pub mod baby_bear_poseidon2 {
)
}


pub fn default_fri_config() -> FriConfig<ChallengeMmcs> {
let perm = my_perm();
let perm16 = my_perm16();
let hash = MyHash::new(perm.clone());
let compress = MyCompress::new(perm.clone());
let compress = MyCompress::new(perm16.clone());
let challenge_mmcs = ChallengeMmcs::new(ValMmcs::new(hash, compress));
let num_queries = match std::env::var("FRI_QUERIES") {
Ok(value) => value.parse().unwrap(),
Expand All @@ -465,8 +489,9 @@ pub mod baby_bear_poseidon2 {

pub fn compressed_fri_config() -> FriConfig<ChallengeMmcs> {
let perm = my_perm();
let perm16 = my_perm16();
let hash = MyHash::new(perm.clone());
let compress = MyCompress::new(perm.clone());
let compress = MyCompress::new(perm16.clone());
let challenge_mmcs = ChallengeMmcs::new(ValMmcs::new(hash, compress));
let num_queries = match std::env::var("FRI_QUERIES") {
Ok(value) => value.parse().unwrap(),
Expand Down Expand Up @@ -496,8 +521,9 @@ pub mod baby_bear_poseidon2 {
impl BabyBearPoseidon2 {
pub fn new() -> Self {
let perm = my_perm();
let perm16 = my_perm16();
let hash = MyHash::new(perm.clone());
let compress = MyCompress::new(perm.clone());
let compress = MyCompress::new(perm16.clone());
let val_mmcs = ValMmcs::new(hash, compress);
let dft = Dft {};
let fri_config = default_fri_config();
Expand All @@ -511,8 +537,9 @@ pub mod baby_bear_poseidon2 {

pub fn compressed() -> Self {
let perm = my_perm();
let perm16 = my_perm16();
let hash = MyHash::new(perm.clone());
let compress = MyCompress::new(perm.clone());
let compress = MyCompress::new(perm16.clone());
let val_mmcs = ValMmcs::new(hash, compress);
let dft = Dft {};
let fri_config = compressed_fri_config();
Expand Down
2 changes: 2 additions & 0 deletions primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ p3-baby-bear = { workspace = true }
p3-poseidon2 = { workspace = true }
p3-symmetric = { workspace = true }
itertools = "0.12.1"
rand_xoshiro = "0.6.0"
rand = "0.8.5"
116 changes: 107 additions & 9 deletions primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@

use lazy_static::lazy_static;
use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear};
use p3_field::AbstractField;
use p3_field::{AbstractField, PrimeField32};
use p3_poseidon2::{Poseidon2, Poseidon2ExternalMatrixGeneral};

use rand_xoshiro::Xoroshiro128Plus;
use rand::{SeedableRng, Rng};
use rand::distributions::Standard;

lazy_static! {
// These constants are created by a RNG.

Expand Down Expand Up @@ -1099,7 +1103,41 @@
];
}

pub fn poseidon2_init(
lazy_static! {
pub static ref RC_24_29: [[BabyBear; 24]; 30] = {
let mut rng = &mut Xoroshiro128Plus::seed_from_u64(1);

Check warning on line 1108 in primitives/src/lib.rs

View workflow job for this annotation

GitHub Actions / Groth16

variable does not need to be mutable

Check warning on line 1108 in primitives/src/lib.rs

View workflow job for this annotation

GitHub Actions / Test (ARM)

variable does not need to be mutable

Check warning on line 1108 in primitives/src/lib.rs

View workflow job for this annotation

GitHub Actions / Test (x86-64)

variable does not need to be mutable
let mut external_constants: Vec<[BabyBear; 24]> = rng

Check warning on line 1109 in primitives/src/lib.rs

View workflow job for this annotation

GitHub Actions / Groth16

variable does not need to be mutable

Check warning on line 1109 in primitives/src/lib.rs

View workflow job for this annotation

GitHub Actions / Test (ARM)

variable does not need to be mutable

Check warning on line 1109 in primitives/src/lib.rs

View workflow job for this annotation

GitHub Actions / Test (x86-64)

variable does not need to be mutable
.sample_iter(Standard)
.take(8)
.collect();
let internal_constants: Vec<BabyBear> = rng
.sample_iter(Standard)
.take(21)
.collect();

let mut array: [[BabyBear; 24]; 30] = Default::default(); // Initializes with default values

for (i, value) in external_constants.iter().take(4).enumerate() {
array[i] = *value;
}
for (i, value) in internal_constants.iter().enumerate() {
array[i + 4][0] = *value;
}
for (i, value) in external_constants.iter().skip(4).enumerate() {
array[i + 25] = *value;
}

array
};

pub static ref RC_24_29_U32: [[u32; 24]; 30] = {
RC_24_29.map(|sub_arr| {
sub_arr.map(|x| x.as_canonical_u32())
})
};
}

pub fn poseidon2_16_init(
) -> Poseidon2<BabyBear, Poseidon2ExternalMatrixGeneral, DiffusionMatrixBabyBear, 16, 7> {
const ROUNDS_F: usize = 8;
const ROUNDS_P: usize = 13;
Expand All @@ -1121,33 +1159,93 @@
)
}

pub fn poseidon2_24_init(
) -> Poseidon2<BabyBear, Poseidon2ExternalMatrixGeneral, DiffusionMatrixBabyBear, 24, 7> {
const ROUNDS_F: usize = 8;
const ROUNDS_P: usize = 21;
let mut round_constants = RC_24_29.to_vec();
let internal_start = ROUNDS_F / 2;
let internal_end = (ROUNDS_F / 2) + ROUNDS_P;
let internal_round_constants = round_constants
.drain(internal_start..internal_end)
.map(|vec| vec[0])
.collect::<Vec<_>>();
let external_round_constants = round_constants;
Poseidon2::new(
ROUNDS_F,
external_round_constants,
Poseidon2ExternalMatrixGeneral,
ROUNDS_P,
internal_round_constants,
DiffusionMatrixBabyBear,
)
}

#[cfg(test)]
mod tests {
use super::*;
use p3_symmetric::Permutation;

#[test]
fn test_24_permutation() {
let h1 = poseidon2_24_init();

type Perm = Poseidon2<BabyBear, Poseidon2ExternalMatrixGeneral, DiffusionMatrixBabyBear, 24, 7>;
let h2 = Perm::new_from_rng_128(
Poseidon2ExternalMatrixGeneral,
DiffusionMatrixBabyBear,
&mut Xoroshiro128Plus::seed_from_u64(1),
);

let mut input1: [BabyBear; 24] = [
886409618, 1327899896, 1902407911, 591953491, 648428576, 1844789031, 1198336108,
355597330, 1799586834, 59617783, 790334801, 1968791836, 559272107, 31054313,
1042221543, 474748436, 135686258, 263665994, 1962340735, 1741539604, 449439011,
1131357108, 50869465, 1589724894,
]
.map(BabyBear::from_canonical_u32);
let mut input2: [BabyBear; 24] = [
886409618, 1327899896, 1902407911, 591953491, 648428576, 1844789031, 1198336108,
355597330, 1799586834, 59617783, 790334801, 1968791836, 559272107, 31054313,
1042221543, 474748436, 135686258, 263665994, 1962340735, 1741539604, 449439011,
1131357108, 50869465, 1589724894,
]
.map(BabyBear::from_canonical_u32);

h1.permute_mut(&mut input1);
h2.permute_mut(&mut input2);

assert_eq!(input1, input2);
}
}

use p3_symmetric::{CryptographicHasher, PaddingFreeSponge};

pub fn poseidon2_hash(input: Vec<BabyBear>) -> [BabyBear; 8] {
POSEIDON2_HASHER.hash_iter(input)
}

pub fn poseidon2_hasher() -> PaddingFreeSponge<
Poseidon2<BabyBear, Poseidon2ExternalMatrixGeneral, DiffusionMatrixBabyBear, 16, 7>,
Poseidon2<BabyBear, Poseidon2ExternalMatrixGeneral, DiffusionMatrixBabyBear, 24, 7>,
24,
16,
8,
8,
> {
let hasher = poseidon2_init();
let hasher = poseidon2_24_init();
PaddingFreeSponge::<
Poseidon2<BabyBear, Poseidon2ExternalMatrixGeneral, DiffusionMatrixBabyBear, 16, 7>,
Poseidon2<BabyBear, Poseidon2ExternalMatrixGeneral, DiffusionMatrixBabyBear, 24, 7>,
24,
16,
8,
8,
>::new(hasher)
}

lazy_static! {
pub static ref POSEIDON2_HASHER: PaddingFreeSponge::<
Poseidon2<BabyBear, Poseidon2ExternalMatrixGeneral, DiffusionMatrixBabyBear, 16, 7>,
Poseidon2<BabyBear, Poseidon2ExternalMatrixGeneral, DiffusionMatrixBabyBear, 24, 7>,
24,
16,
8,
8,
> = poseidon2_hasher();
}

Expand Down
2 changes: 1 addition & 1 deletion recursion/core/src/air/public_values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::mem::size_of;

pub const PV_DIGEST_NUM_WORDS: usize = 8;

pub const CHALLENGER_STATE_NUM_ELTS: usize = 50;
pub const CHALLENGER_STATE_NUM_ELTS: usize = PERMUTATION_WIDTH * 3 + 2;

pub const RECURSIVE_PROOF_NUM_PV_ELTS: usize = size_of::<RecursionPublicValues<u8>>();

Expand Down
2 changes: 1 addition & 1 deletion recursion/core/src/poseidon2/columns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub struct Poseidon2Cols<T: Copy> {
pub dst_input: T,
pub left_input: T,
pub right_input: T,
pub rounds: [T; 24], // 1 round for memory input; 1 round for initialize; 8 rounds for external; 13 rounds for internal; 1 round for memory output
pub rounds: [T; 32], // 1 round for memory input; 1 round for initialize; 8 rounds for external; 21 rounds for internal; 1 round for memory output
pub round_specific_cols: RoundSpecificCols<T>,
}

Expand Down
Loading
Loading