sp1_stark/
bb31_poseidon2.rs

1#![allow(missing_docs)]
2
3use crate::{Com, StarkGenericConfig, ZeroCommitment};
4use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear};
5use p3_challenger::DuplexChallenger;
6use p3_commit::ExtensionMmcs;
7use p3_dft::Radix2DitParallel;
8use p3_field::{extension::BinomialExtensionField, AbstractField, Field};
9use p3_fri::{
10    BatchOpening, CommitPhaseProofStep, FriConfig, FriProof, QueryProof, TwoAdicFriPcs,
11    TwoAdicFriPcsProof,
12};
13use p3_merkle_tree::FieldMerkleTreeMmcs;
14use p3_poseidon2::{Poseidon2, Poseidon2ExternalMatrixGeneral};
15use p3_symmetric::{Hash, PaddingFreeSponge, TruncatedPermutation};
16use serde::{Deserialize, Serialize};
17use sp1_primitives::poseidon2_init;
18
19pub const DIGEST_SIZE: usize = 8;
20
21/// A configuration for inner recursion.
22pub type InnerVal = BabyBear;
23pub type InnerChallenge = BinomialExtensionField<InnerVal, 4>;
24pub type InnerPerm =
25    Poseidon2<InnerVal, Poseidon2ExternalMatrixGeneral, DiffusionMatrixBabyBear, 16, 7>;
26pub type InnerHash = PaddingFreeSponge<InnerPerm, 16, 8, DIGEST_SIZE>;
27pub type InnerDigestHash = Hash<InnerVal, InnerVal, DIGEST_SIZE>;
28pub type InnerDigest = [InnerVal; DIGEST_SIZE];
29pub type InnerCompress = TruncatedPermutation<InnerPerm, 2, 8, 16>;
30pub type InnerValMmcs = FieldMerkleTreeMmcs<
31    <InnerVal as Field>::Packing,
32    <InnerVal as Field>::Packing,
33    InnerHash,
34    InnerCompress,
35    8,
36>;
37pub type InnerChallengeMmcs = ExtensionMmcs<InnerVal, InnerChallenge, InnerValMmcs>;
38pub type InnerChallenger = DuplexChallenger<InnerVal, InnerPerm, 16, 8>;
39pub type InnerDft = Radix2DitParallel;
40pub type InnerPcs = TwoAdicFriPcs<InnerVal, InnerDft, InnerValMmcs, InnerChallengeMmcs>;
41pub type InnerQueryProof = QueryProof<InnerChallenge, InnerChallengeMmcs>;
42pub type InnerCommitPhaseStep = CommitPhaseProofStep<InnerChallenge, InnerChallengeMmcs>;
43pub type InnerFriProof = FriProof<InnerChallenge, InnerChallengeMmcs, InnerVal>;
44pub type InnerBatchOpening = BatchOpening<InnerVal, InnerValMmcs>;
45pub type InnerPcsProof =
46    TwoAdicFriPcsProof<InnerVal, InnerChallenge, InnerValMmcs, InnerChallengeMmcs>;
47
48/// The permutation for inner recursion.
49#[must_use]
50pub fn inner_perm() -> InnerPerm {
51    poseidon2_init()
52}
53
54/// The FRI config for sp1 proofs.
55#[must_use]
56pub fn sp1_fri_config() -> FriConfig<InnerChallengeMmcs> {
57    let perm = inner_perm();
58    let hash = InnerHash::new(perm.clone());
59    let compress = InnerCompress::new(perm.clone());
60    let challenge_mmcs = InnerChallengeMmcs::new(InnerValMmcs::new(hash, compress));
61    let num_queries = match std::env::var("FRI_QUERIES") {
62        Ok(value) => value.parse().unwrap(),
63        Err(_) => 100,
64    };
65    FriConfig { log_blowup: 1, num_queries, proof_of_work_bits: 16, mmcs: challenge_mmcs }
66}
67
68/// The FRI config for inner recursion.
69#[must_use]
70pub fn inner_fri_config() -> FriConfig<InnerChallengeMmcs> {
71    let perm = inner_perm();
72    let hash = InnerHash::new(perm.clone());
73    let compress = InnerCompress::new(perm.clone());
74    let challenge_mmcs = InnerChallengeMmcs::new(InnerValMmcs::new(hash, compress));
75    let num_queries = match std::env::var("FRI_QUERIES") {
76        Ok(value) => value.parse().unwrap(),
77        Err(_) => 100,
78    };
79    FriConfig { log_blowup: 1, num_queries, proof_of_work_bits: 16, mmcs: challenge_mmcs }
80}
81
82/// The recursion config used for recursive reduce circuit.
83#[derive(Deserialize)]
84#[serde(from = "std::marker::PhantomData<BabyBearPoseidon2Inner>")]
85pub struct BabyBearPoseidon2Inner {
86    pub perm: InnerPerm,
87    pub pcs: InnerPcs,
88}
89
90impl Clone for BabyBearPoseidon2Inner {
91    fn clone(&self) -> Self {
92        Self::new()
93    }
94}
95
96impl Serialize for BabyBearPoseidon2Inner {
97    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
98    where
99        S: serde::Serializer,
100    {
101        std::marker::PhantomData::<BabyBearPoseidon2Inner>.serialize(serializer)
102    }
103}
104
105impl From<std::marker::PhantomData<BabyBearPoseidon2Inner>> for BabyBearPoseidon2Inner {
106    fn from(_: std::marker::PhantomData<BabyBearPoseidon2Inner>) -> Self {
107        Self::new()
108    }
109}
110
111impl BabyBearPoseidon2Inner {
112    #[must_use]
113    pub fn new() -> Self {
114        let perm = inner_perm();
115        let hash = InnerHash::new(perm.clone());
116        let compress = InnerCompress::new(perm.clone());
117        let val_mmcs = InnerValMmcs::new(hash, compress);
118        let dft = InnerDft {};
119        let fri_config = inner_fri_config();
120        let pcs = InnerPcs::new(27, dft, val_mmcs, fri_config);
121        Self { perm, pcs }
122    }
123}
124
125impl Default for BabyBearPoseidon2Inner {
126    fn default() -> Self {
127        Self::new()
128    }
129}
130
131impl StarkGenericConfig for BabyBearPoseidon2Inner {
132    type Val = InnerVal;
133    type Domain = <InnerPcs as p3_commit::Pcs<InnerChallenge, InnerChallenger>>::Domain;
134    type Pcs = InnerPcs;
135    type Challenge = InnerChallenge;
136    type Challenger = InnerChallenger;
137
138    fn pcs(&self) -> &Self::Pcs {
139        &self.pcs
140    }
141
142    fn challenger(&self) -> Self::Challenger {
143        InnerChallenger::new(self.perm.clone())
144    }
145}
146
147impl ZeroCommitment<BabyBearPoseidon2Inner> for InnerPcs {
148    fn zero_commitment(&self) -> Com<BabyBearPoseidon2Inner> {
149        InnerDigestHash::from([InnerVal::zero(); DIGEST_SIZE])
150    }
151}
152
153pub mod baby_bear_poseidon2 {
154
155    use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear};
156    use p3_challenger::DuplexChallenger;
157    use p3_commit::ExtensionMmcs;
158    use p3_dft::Radix2DitParallel;
159    use p3_field::{extension::BinomialExtensionField, AbstractField, Field};
160    use p3_fri::{FriConfig, TwoAdicFriPcs};
161    use p3_merkle_tree::FieldMerkleTreeMmcs;
162    use p3_poseidon2::{Poseidon2, Poseidon2ExternalMatrixGeneral};
163    use p3_symmetric::{Hash, PaddingFreeSponge, TruncatedPermutation};
164    use serde::{Deserialize, Serialize};
165    use sp1_primitives::RC_16_30;
166
167    use crate::{Com, StarkGenericConfig, ZeroCommitment, DIGEST_SIZE};
168
169    pub type Val = BabyBear;
170    pub type Challenge = BinomialExtensionField<Val, 4>;
171
172    pub type Perm = Poseidon2<Val, Poseidon2ExternalMatrixGeneral, DiffusionMatrixBabyBear, 16, 7>;
173    pub type MyHash = PaddingFreeSponge<Perm, 16, 8, DIGEST_SIZE>;
174    pub type DigestHash = Hash<Val, Val, DIGEST_SIZE>;
175    pub type MyCompress = TruncatedPermutation<Perm, 2, 8, 16>;
176    pub type ValMmcs = FieldMerkleTreeMmcs<
177        <Val as Field>::Packing,
178        <Val as Field>::Packing,
179        MyHash,
180        MyCompress,
181        8,
182    >;
183    pub type ChallengeMmcs = ExtensionMmcs<Val, Challenge, ValMmcs>;
184    pub type Dft = Radix2DitParallel;
185    pub type Challenger = DuplexChallenger<Val, Perm, 16, 8>;
186    type Pcs = TwoAdicFriPcs<Val, Dft, ValMmcs, ChallengeMmcs>;
187
188    #[must_use]
189    pub fn my_perm() -> Perm {
190        const ROUNDS_F: usize = 8;
191        const ROUNDS_P: usize = 13;
192        let mut round_constants = RC_16_30.to_vec();
193        let internal_start = ROUNDS_F / 2;
194        let internal_end = (ROUNDS_F / 2) + ROUNDS_P;
195        let internal_round_constants = round_constants
196            .drain(internal_start..internal_end)
197            .map(|vec| vec[0])
198            .collect::<Vec<_>>();
199        let external_round_constants = round_constants;
200        Perm::new(
201            ROUNDS_F,
202            external_round_constants,
203            Poseidon2ExternalMatrixGeneral,
204            ROUNDS_P,
205            internal_round_constants,
206            DiffusionMatrixBabyBear,
207        )
208    }
209
210    #[must_use]
211    pub fn default_fri_config() -> FriConfig<ChallengeMmcs> {
212        let perm = my_perm();
213        let hash = MyHash::new(perm.clone());
214        let compress = MyCompress::new(perm.clone());
215        let challenge_mmcs = ChallengeMmcs::new(ValMmcs::new(hash, compress));
216        let num_queries = match std::env::var("FRI_QUERIES") {
217            Ok(value) => value.parse().unwrap(),
218            Err(_) => 100,
219        };
220        FriConfig { log_blowup: 1, num_queries, proof_of_work_bits: 16, mmcs: challenge_mmcs }
221    }
222
223    #[must_use]
224    pub fn compressed_fri_config() -> FriConfig<ChallengeMmcs> {
225        let perm = my_perm();
226        let hash = MyHash::new(perm.clone());
227        let compress = MyCompress::new(perm.clone());
228        let challenge_mmcs = ChallengeMmcs::new(ValMmcs::new(hash, compress));
229        let num_queries = match std::env::var("FRI_QUERIES") {
230            Ok(value) => value.parse().unwrap(),
231            Err(_) => 50,
232        };
233        FriConfig { log_blowup: 2, num_queries, proof_of_work_bits: 16, mmcs: challenge_mmcs }
234    }
235
236    #[must_use]
237    pub fn ultra_compressed_fri_config() -> FriConfig<ChallengeMmcs> {
238        let perm = my_perm();
239        let hash = MyHash::new(perm.clone());
240        let compress = MyCompress::new(perm.clone());
241        let challenge_mmcs = ChallengeMmcs::new(ValMmcs::new(hash, compress));
242        let num_queries = match std::env::var("FRI_QUERIES") {
243            Ok(value) => value.parse().unwrap(),
244            Err(_) => 33,
245        };
246        FriConfig { log_blowup: 3, num_queries, proof_of_work_bits: 16, mmcs: challenge_mmcs }
247    }
248
249    enum BabyBearPoseidon2Type {
250        Default,
251        Compressed,
252    }
253
254    #[derive(Deserialize)]
255    #[serde(from = "std::marker::PhantomData<BabyBearPoseidon2>")]
256    pub struct BabyBearPoseidon2 {
257        pub perm: Perm,
258        pcs: Pcs,
259        config_type: BabyBearPoseidon2Type,
260    }
261
262    impl BabyBearPoseidon2 {
263        #[must_use]
264        pub fn new() -> Self {
265            let perm = my_perm();
266            let hash = MyHash::new(perm.clone());
267            let compress = MyCompress::new(perm.clone());
268            let val_mmcs = ValMmcs::new(hash, compress);
269            let dft = Dft {};
270            let fri_config = default_fri_config();
271            let pcs = Pcs::new(27, dft, val_mmcs, fri_config);
272            Self { pcs, perm, config_type: BabyBearPoseidon2Type::Default }
273        }
274
275        #[must_use]
276        pub fn compressed() -> Self {
277            let perm = my_perm();
278            let hash = MyHash::new(perm.clone());
279            let compress = MyCompress::new(perm.clone());
280            let val_mmcs = ValMmcs::new(hash, compress);
281            let dft = Dft {};
282            let fri_config = compressed_fri_config();
283            let pcs = Pcs::new(27, dft, val_mmcs, fri_config);
284            Self { pcs, perm, config_type: BabyBearPoseidon2Type::Compressed }
285        }
286
287        #[must_use]
288        pub fn ultra_compressed() -> Self {
289            let perm = my_perm();
290            let hash = MyHash::new(perm.clone());
291            let compress = MyCompress::new(perm.clone());
292            let val_mmcs = ValMmcs::new(hash, compress);
293            let dft = Dft {};
294            let fri_config = ultra_compressed_fri_config();
295            let pcs = Pcs::new(27, dft, val_mmcs, fri_config);
296            Self { pcs, perm, config_type: BabyBearPoseidon2Type::Compressed }
297        }
298    }
299
300    impl Clone for BabyBearPoseidon2 {
301        fn clone(&self) -> Self {
302            match self.config_type {
303                BabyBearPoseidon2Type::Default => Self::new(),
304                BabyBearPoseidon2Type::Compressed => Self::compressed(),
305            }
306        }
307    }
308
309    impl Default for BabyBearPoseidon2 {
310        fn default() -> Self {
311            Self::new()
312        }
313    }
314
315    /// Implement serialization manually instead of using serde to avoid cloing the config.
316    impl Serialize for BabyBearPoseidon2 {
317        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
318        where
319            S: serde::Serializer,
320        {
321            std::marker::PhantomData::<BabyBearPoseidon2>.serialize(serializer)
322        }
323    }
324
325    impl From<std::marker::PhantomData<BabyBearPoseidon2>> for BabyBearPoseidon2 {
326        fn from(_: std::marker::PhantomData<BabyBearPoseidon2>) -> Self {
327            Self::new()
328        }
329    }
330
331    impl StarkGenericConfig for BabyBearPoseidon2 {
332        type Val = BabyBear;
333        type Domain = <Pcs as p3_commit::Pcs<Challenge, Challenger>>::Domain;
334        type Pcs = Pcs;
335        type Challenge = Challenge;
336        type Challenger = Challenger;
337
338        fn pcs(&self) -> &Self::Pcs {
339            &self.pcs
340        }
341
342        fn challenger(&self) -> Self::Challenger {
343            Challenger::new(self.perm.clone())
344        }
345    }
346
347    impl ZeroCommitment<BabyBearPoseidon2> for Pcs {
348        fn zero_commitment(&self) -> Com<BabyBearPoseidon2> {
349            DigestHash::from([Val::zero(); DIGEST_SIZE])
350        }
351    }
352}