1use std::{any::type_name, sync::Arc};
2
3use openvm_stark_backend::{
4 config::StarkConfig,
5 interaction::fri_log_up::FriLogUpPhase,
6 p3_challenger::DuplexChallenger,
7 p3_commit::ExtensionMmcs,
8 p3_field::{extension::BinomialExtensionField, Field},
9 prover::{
10 cpu::{CpuBackend, CpuDevice},
11 MultiTraceStarkProver,
12 },
13};
14use p3_dft::Radix2DitParallel;
15use p3_fri::{FriConfig, TwoAdicFriPcs};
16use p3_goldilocks::{Goldilocks, MdsMatrixGoldilocks};
17use p3_merkle_tree::MerkleTreeMmcs;
18use p3_poseidon::Poseidon;
19use p3_symmetric::{CryptographicPermutation, PaddingFreeSponge, TruncatedPermutation};
20use rand::{rngs::StdRng, SeedableRng};
21
22use super::instrument::{HashStatistics, Instrumented, StarkHashStatistics};
23use crate::{
24 assert_sc_compatible_with_serde,
25 config::fri_params::SecurityParameters,
26 engine::{StarkEngine, StarkEngineWithHashInstrumentation},
27};
28
29const RATE: usize = 4;
30const WIDTH: usize = 8; const DIGEST_WIDTH: usize = 4;
33
34type Val = Goldilocks;
35type PackedVal = <Val as Field>::Packing;
36type Challenge = BinomialExtensionField<Val, 2>;
37type Perm = Poseidon<Val, MdsMatrixGoldilocks, WIDTH, 7>;
38type InstrPerm = Instrumented<Perm>;
39
40type Hash<P> = PaddingFreeSponge<P, WIDTH, RATE, DIGEST_WIDTH>;
42type Compress<P> = TruncatedPermutation<P, 2, DIGEST_WIDTH, WIDTH>;
43type ValMmcs<P> =
44 MerkleTreeMmcs<PackedVal, <Val as Field>::Packing, Hash<P>, Compress<P>, DIGEST_WIDTH>;
45type ChallengeMmcs<P> = ExtensionMmcs<Val, Challenge, ValMmcs<P>>;
46pub type Challenger<P> = DuplexChallenger<Val, P, WIDTH, RATE>;
47type Dft = Radix2DitParallel<Val>;
48type Pcs<P> = TwoAdicFriPcs<Val, Dft, ValMmcs<P>, ChallengeMmcs<P>>;
49type RapPhase<P> = FriLogUpPhase<Val, Challenge, Challenger<P>>;
50
51pub type GoldilocksPermutationConfig<P> =
52 StarkConfig<Pcs<P>, RapPhase<P>, Challenge, Challenger<P>>;
53pub type GoldilocksPoseidonConfig = GoldilocksPermutationConfig<Perm>;
54pub type GoldilocksPoseidonEngine = GoldilocksPermutationEngine<Perm>;
55
56assert_sc_compatible_with_serde!(GoldilocksPoseidonConfig);
57
58pub struct GoldilocksPermutationEngine<P>
59where
60 P: CryptographicPermutation<[Val; WIDTH]>
61 + CryptographicPermutation<[PackedVal; WIDTH]>
62 + Clone,
63{
64 security_params: SecurityParameters,
65 pub device: CpuDevice<GoldilocksPermutationConfig<P>>,
66 pub perm: P,
67 pub max_constraint_degree: usize,
68}
69
70impl<P> StarkEngine for GoldilocksPermutationEngine<P>
71where
72 P: CryptographicPermutation<[Val; WIDTH]>
73 + CryptographicPermutation<[PackedVal; WIDTH]>
74 + Clone,
75{
76 type SC = GoldilocksPermutationConfig<P>;
77 type PB = CpuBackend<Self::SC>;
78 type PD = CpuDevice<Self::SC>;
79
80 fn config(&self) -> &GoldilocksPermutationConfig<P> {
81 &self.device.config
82 }
83
84 fn device(&self) -> &CpuDevice<GoldilocksPermutationConfig<P>> {
85 &self.device
86 }
87
88 fn prover(&self) -> MultiTraceStarkProver<GoldilocksPermutationConfig<P>> {
89 MultiTraceStarkProver::new(
90 CpuBackend::default(),
91 self.device.clone(),
92 self.new_challenger(),
93 )
94 }
95
96 fn max_constraint_degree(&self) -> Option<usize> {
97 Some(self.max_constraint_degree)
98 }
99
100 fn new_challenger(&self) -> Challenger<P> {
101 Challenger::new(self.perm.clone())
102 }
103}
104
105impl<P> StarkEngineWithHashInstrumentation for GoldilocksPermutationEngine<Instrumented<P>>
106where
107 P: CryptographicPermutation<[Val; WIDTH]>
108 + CryptographicPermutation<[PackedVal; WIDTH]>
109 + Clone,
110{
111 fn clear_instruments(&mut self) {
112 self.perm.input_lens_by_type.lock().unwrap().clear();
113 }
114 fn stark_hash_statistics<T>(&self, custom: T) -> StarkHashStatistics<T> {
115 let counter = self.perm.input_lens_by_type.lock().unwrap();
116 let permutations = counter.iter().fold(0, |total, (name, lens)| {
117 if name == type_name::<[Val; WIDTH]>() {
118 let count: usize = lens.iter().sum();
119 println!("Permutation: {name}, Count: {count}");
120 total + count
121 } else {
122 panic!("Permutation type not yet supported: {}", name);
123 }
124 });
125
126 StarkHashStatistics {
127 name: type_name::<P>().to_string(),
128 stats: HashStatistics { permutations },
129 fri_params: self.security_params.fri_params,
130 custom,
131 }
132 }
133}
134
135pub fn default_engine() -> GoldilocksPoseidonEngine {
137 let perm = random_perm();
138 engine_from_perm(perm, SecurityParameters::standard_fast())
139}
140
141pub fn default_config(perm: &Perm) -> GoldilocksPoseidonConfig {
143 config_from_perm(perm, SecurityParameters::standard_fast())
144}
145
146pub fn engine_from_perm<P>(
147 perm: P,
148 security_params: SecurityParameters,
149) -> GoldilocksPermutationEngine<P>
150where
151 P: CryptographicPermutation<[Val; WIDTH]>
152 + CryptographicPermutation<[PackedVal; WIDTH]>
153 + Clone,
154{
155 let max_constraint_degree = security_params.fri_params.max_constraint_degree();
156 let config = config_from_perm(&perm, security_params.clone());
157 GoldilocksPermutationEngine {
158 device: CpuDevice::new(Arc::new(config), security_params.fri_params.log_blowup),
159 perm,
160 security_params,
161 max_constraint_degree,
162 }
163}
164
165pub fn config_from_perm<P>(
166 perm: &P,
167 security_params: SecurityParameters,
168) -> GoldilocksPermutationConfig<P>
169where
170 P: CryptographicPermutation<[Val; WIDTH]>
171 + CryptographicPermutation<[PackedVal; WIDTH]>
172 + Clone,
173{
174 let hash = Hash::new(perm.clone());
175 let compress = Compress::new(perm.clone());
176 let val_mmcs = ValMmcs::new(hash, compress);
177 let challenge_mmcs = ChallengeMmcs::new(val_mmcs.clone());
178 let dft = Dft::default();
179 let SecurityParameters {
180 fri_params,
181 log_up_params,
182 } = security_params;
183 let fri_config = FriConfig {
184 log_blowup: fri_params.log_blowup,
185 log_final_poly_len: fri_params.log_final_poly_len,
186 num_queries: fri_params.num_queries,
187 proof_of_work_bits: fri_params.proof_of_work_bits,
188 mmcs: challenge_mmcs,
189 };
190 let pcs = Pcs::new(dft, val_mmcs, fri_config);
191 let rap_phase = FriLogUpPhase::new(log_up_params, fri_params.log_blowup);
192 GoldilocksPermutationConfig::new(pcs, rap_phase)
193}
194
195pub fn random_perm() -> Perm {
196 let seed = [42; 32];
197 let mut rng = StdRng::from_seed(seed);
198 Perm::new_from_rng(4, 22, MdsMatrixGoldilocks, &mut rng)
199}
200
201pub fn random_instrumented_perm() -> InstrPerm {
202 let perm = random_perm();
203 Instrumented::new(perm)
204}