sp1_recursion_program/
hints.rs

1use p3_baby_bear::BabyBear;
2use p3_challenger::DuplexChallenger;
3use p3_commit::TwoAdicMultiplicativeCoset;
4use p3_field::{AbstractExtensionField, AbstractField, TwoAdicField};
5
6use sp1_core_machine::riscv::RiscvAir;
7use sp1_recursion_compiler::{
8    config::InnerConfig,
9    ir::{Array, Builder, Config, Ext, Felt, MemVariable, Var, Variable},
10};
11use sp1_recursion_core::{air::Block, runtime::PERMUTATION_WIDTH};
12use sp1_stark::{
13    air::{MachineAir, PV_DIGEST_NUM_WORDS},
14    baby_bear_poseidon2::BabyBearPoseidon2,
15    AirOpenedValues, ChipOpenedValues, Com, InnerChallenge, InnerDigest, InnerDigestHash,
16    InnerPcsProof, InnerPerm, InnerVal, ShardCommitment, ShardOpenedValues, StarkGenericConfig,
17    Word,
18};
19
20use crate::{
21    challenger::DuplexChallengerVariable,
22    fri::TwoAdicMultiplicativeCosetVariable,
23    machine::*,
24    stark::{ShardProofHint, VerifyingKeyHint},
25    types::{
26        AirOpenedValuesVariable, ChipOpenedValuesVariable, QuotientData, QuotientDataValues,
27        Sha256DigestVariable, ShardCommitmentVariable, ShardOpenedValuesVariable,
28        ShardProofVariable, VerifyingKeyVariable,
29    },
30    utils::{get_chip_quotient_data, get_preprocessed_data, get_sorted_indices},
31};
32
33pub trait Hintable<C: Config> {
34    type HintVariable: Variable<C>;
35
36    fn read(builder: &mut Builder<C>) -> Self::HintVariable;
37
38    fn write(&self) -> Vec<Vec<Block<C::F>>>;
39
40    fn witness(variable: &Self::HintVariable, builder: &mut Builder<C>) {
41        let target = Self::read(builder);
42        builder.assign(variable.clone(), target);
43    }
44}
45
46type C = InnerConfig;
47
48impl Hintable<C> for usize {
49    type HintVariable = Var<InnerVal>;
50
51    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
52        builder.hint_var()
53    }
54
55    fn write(&self) -> Vec<Vec<Block<InnerVal>>> {
56        vec![vec![Block::from(InnerVal::from_canonical_usize(*self))]]
57    }
58}
59
60impl Hintable<C> for InnerVal {
61    type HintVariable = Felt<InnerVal>;
62
63    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
64        builder.hint_felt()
65    }
66
67    fn write(&self) -> Vec<Vec<Block<<C as Config>::F>>> {
68        vec![vec![Block::from(*self)]]
69    }
70}
71
72impl Hintable<C> for InnerChallenge {
73    type HintVariable = Ext<InnerVal, InnerChallenge>;
74
75    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
76        builder.hint_ext()
77    }
78
79    fn write(&self) -> Vec<Vec<Block<<C as Config>::F>>> {
80        vec![vec![Block::from((*self).as_base_slice())]]
81    }
82}
83
84impl Hintable<C> for [Word<BabyBear>; PV_DIGEST_NUM_WORDS] {
85    type HintVariable = Sha256DigestVariable<C>;
86
87    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
88        let bytes = builder.hint_felts();
89        Sha256DigestVariable { bytes }
90    }
91
92    fn write(&self) -> Vec<Vec<Block<<C as Config>::F>>> {
93        vec![self.iter().flat_map(|w| w.0.iter().map(|f| Block::from(*f))).collect::<Vec<_>>()]
94    }
95}
96
97impl Hintable<C> for QuotientDataValues {
98    type HintVariable = QuotientData<C>;
99
100    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
101        let log_quotient_degree = usize::read(builder);
102        let quotient_size = usize::read(builder);
103
104        QuotientData { log_quotient_degree, quotient_size }
105    }
106
107    fn write(&self) -> Vec<Vec<Block<<C as Config>::F>>> {
108        let mut buffer = Vec::new();
109        buffer.extend(usize::write(&self.log_quotient_degree));
110        buffer.extend(usize::write(&self.quotient_size));
111
112        buffer
113    }
114}
115
116impl Hintable<C> for TwoAdicMultiplicativeCoset<InnerVal> {
117    type HintVariable = TwoAdicMultiplicativeCosetVariable<C>;
118
119    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
120        let log_n = usize::read(builder);
121        let shift = InnerVal::read(builder);
122        let g_val = InnerVal::read(builder);
123        let size = usize::read(builder);
124
125        // Initialize a domain.
126        TwoAdicMultiplicativeCosetVariable::<C> { log_n, size, shift, g: g_val }
127    }
128
129    fn write(&self) -> Vec<Vec<Block<<C as Config>::F>>> {
130        let mut vec = Vec::new();
131        vec.extend(usize::write(&self.log_n));
132        vec.extend(InnerVal::write(&self.shift));
133        vec.extend(InnerVal::write(&InnerVal::two_adic_generator(self.log_n)));
134        vec.extend(usize::write(&(1usize << (self.log_n))));
135        vec
136    }
137}
138
139trait VecAutoHintable<C: Config>: Hintable<C> {}
140
141impl<'a, A: MachineAir<BabyBear>> VecAutoHintable<C> for ShardProofHint<'a, BabyBearPoseidon2, A> {}
142impl VecAutoHintable<C> for TwoAdicMultiplicativeCoset<InnerVal> {}
143impl VecAutoHintable<C> for Vec<usize> {}
144impl VecAutoHintable<C> for QuotientDataValues {}
145impl VecAutoHintable<C> for Vec<QuotientDataValues> {}
146impl VecAutoHintable<C> for Vec<InnerVal> {}
147
148impl<I: VecAutoHintable<C>> VecAutoHintable<C> for &I {}
149
150impl<H: Hintable<C>> Hintable<C> for &H {
151    type HintVariable = H::HintVariable;
152
153    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
154        H::read(builder)
155    }
156
157    fn write(&self) -> Vec<Vec<Block<<C as Config>::F>>> {
158        H::write(self)
159    }
160}
161
162impl<I: VecAutoHintable<C>> Hintable<C> for Vec<I>
163where
164    <I as Hintable<C>>::HintVariable: MemVariable<C>,
165{
166    type HintVariable = Array<C, I::HintVariable>;
167
168    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
169        let len = builder.hint_var();
170        let mut arr = builder.dyn_array(len);
171        builder.range(0, len).for_each(|i, builder| {
172            let hint = I::read(builder);
173            builder.set(&mut arr, i, hint);
174        });
175        arr
176    }
177
178    fn write(&self) -> Vec<Vec<Block<<C as Config>::F>>> {
179        let mut stream = Vec::new();
180
181        let len = InnerVal::from_canonical_usize(self.len());
182        stream.push(vec![len.into()]);
183
184        self.iter().for_each(|i| {
185            let comm = I::write(i);
186            stream.extend(comm);
187        });
188
189        stream
190    }
191}
192
193impl Hintable<C> for Vec<usize> {
194    type HintVariable = Array<C, Var<InnerVal>>;
195
196    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
197        builder.hint_vars()
198    }
199
200    fn write(&self) -> Vec<Vec<Block<InnerVal>>> {
201        vec![self.iter().map(|x| Block::from(InnerVal::from_canonical_usize(*x))).collect()]
202    }
203}
204
205impl Hintable<C> for Vec<InnerVal> {
206    type HintVariable = Array<C, Felt<InnerVal>>;
207
208    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
209        builder.hint_felts()
210    }
211
212    fn write(&self) -> Vec<Vec<Block<<C as Config>::F>>> {
213        vec![self.iter().map(|x| Block::from(*x)).collect()]
214    }
215}
216
217impl Hintable<C> for Vec<InnerChallenge> {
218    type HintVariable = Array<C, Ext<InnerVal, InnerChallenge>>;
219
220    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
221        builder.hint_exts()
222    }
223
224    fn write(&self) -> Vec<Vec<Block<<C as Config>::F>>> {
225        vec![self.iter().map(|x| Block::from((*x).as_base_slice())).collect()]
226    }
227}
228
229impl Hintable<C> for AirOpenedValues<InnerChallenge> {
230    type HintVariable = AirOpenedValuesVariable<C>;
231
232    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
233        let local = Vec::<InnerChallenge>::read(builder);
234        let next = Vec::<InnerChallenge>::read(builder);
235        AirOpenedValuesVariable { local, next }
236    }
237
238    fn write(&self) -> Vec<Vec<Block<<C as Config>::F>>> {
239        let mut stream = Vec::new();
240        stream.extend(self.local.write());
241        stream.extend(self.next.write());
242        stream
243    }
244}
245
246impl Hintable<C> for Vec<Vec<InnerChallenge>> {
247    type HintVariable = Array<C, Array<C, Ext<InnerVal, InnerChallenge>>>;
248
249    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
250        let len = builder.hint_var();
251        let mut arr = builder.dyn_array(len);
252        builder.range(0, len).for_each(|i, builder| {
253            let hint = Vec::<InnerChallenge>::read(builder);
254            builder.set(&mut arr, i, hint);
255        });
256        arr
257    }
258
259    fn write(&self) -> Vec<Vec<Block<<C as Config>::F>>> {
260        let mut stream = Vec::new();
261
262        let len = InnerVal::from_canonical_usize(self.len());
263        stream.push(vec![len.into()]);
264
265        self.iter().for_each(|arr| {
266            let comm = Vec::<InnerChallenge>::write(arr);
267            stream.extend(comm);
268        });
269
270        stream
271    }
272}
273
274impl Hintable<C> for ChipOpenedValues<InnerChallenge> {
275    type HintVariable = ChipOpenedValuesVariable<C>;
276
277    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
278        let preprocessed = AirOpenedValues::<InnerChallenge>::read(builder);
279        let main = AirOpenedValues::<InnerChallenge>::read(builder);
280        let permutation = AirOpenedValues::<InnerChallenge>::read(builder);
281        let quotient = Vec::<Vec<InnerChallenge>>::read(builder);
282        let cumulative_sum = InnerChallenge::read(builder);
283        let log_degree = builder.hint_var();
284        ChipOpenedValuesVariable {
285            preprocessed,
286            main,
287            permutation,
288            quotient,
289            cumulative_sum,
290            log_degree,
291        }
292    }
293
294    fn write(&self) -> Vec<Vec<Block<<C as Config>::F>>> {
295        let mut stream = Vec::new();
296        stream.extend(self.preprocessed.write());
297        stream.extend(self.main.write());
298        stream.extend(self.permutation.write());
299        stream.extend(self.quotient.write());
300        stream.extend(self.cumulative_sum.write());
301        stream.extend(self.log_degree.write());
302        stream
303    }
304}
305
306impl Hintable<C> for Vec<ChipOpenedValues<InnerChallenge>> {
307    type HintVariable = Array<C, ChipOpenedValuesVariable<C>>;
308
309    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
310        let len = builder.hint_var();
311        let mut arr = builder.dyn_array(len);
312        builder.range(0, len).for_each(|i, builder| {
313            let hint = ChipOpenedValues::<InnerChallenge>::read(builder);
314            builder.set(&mut arr, i, hint);
315        });
316        arr
317    }
318
319    fn write(&self) -> Vec<Vec<Block<<C as Config>::F>>> {
320        let mut stream = Vec::new();
321
322        let len = InnerVal::from_canonical_usize(self.len());
323        stream.push(vec![len.into()]);
324
325        self.iter().for_each(|arr| {
326            let comm = ChipOpenedValues::<InnerChallenge>::write(arr);
327            stream.extend(comm);
328        });
329
330        stream
331    }
332}
333
334impl Hintable<C> for ShardOpenedValues<InnerChallenge> {
335    type HintVariable = ShardOpenedValuesVariable<C>;
336
337    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
338        let chips = Vec::<ChipOpenedValues<InnerChallenge>>::read(builder);
339        ShardOpenedValuesVariable { chips }
340    }
341
342    fn write(&self) -> Vec<Vec<Block<<C as Config>::F>>> {
343        let mut stream = Vec::new();
344        stream.extend(self.chips.write());
345        stream
346    }
347}
348
349impl Hintable<C> for ShardCommitment<InnerDigestHash> {
350    type HintVariable = ShardCommitmentVariable<C>;
351
352    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
353        let main_commit = InnerDigest::read(builder);
354        let permutation_commit = InnerDigest::read(builder);
355        let quotient_commit = InnerDigest::read(builder);
356        ShardCommitmentVariable { main_commit, permutation_commit, quotient_commit }
357    }
358
359    fn write(&self) -> Vec<Vec<Block<<C as Config>::F>>> {
360        let mut stream = Vec::new();
361        let h: InnerDigest = self.main_commit.into();
362        stream.extend(h.write());
363        let h: InnerDigest = self.permutation_commit.into();
364        stream.extend(h.write());
365        let h: InnerDigest = self.quotient_commit.into();
366        stream.extend(h.write());
367        stream
368    }
369}
370
371impl Hintable<C> for DuplexChallenger<InnerVal, InnerPerm, 16, 8> {
372    type HintVariable = DuplexChallengerVariable<C>;
373
374    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
375        let sponge_state = builder.hint_felts();
376        let nb_inputs = builder.hint_var();
377        let input_buffer = builder.hint_felts();
378        let nb_outputs = builder.hint_var();
379        let output_buffer = builder.hint_felts();
380        DuplexChallengerVariable {
381            sponge_state,
382            nb_inputs,
383            input_buffer,
384            nb_outputs,
385            output_buffer,
386        }
387    }
388
389    fn write(&self) -> Vec<Vec<Block<<C as Config>::F>>> {
390        let mut stream = Vec::new();
391        stream.extend(self.sponge_state.to_vec().write());
392        stream.extend(self.input_buffer.len().write());
393        let mut input_padded = self.input_buffer.to_vec();
394        input_padded.resize(PERMUTATION_WIDTH, InnerVal::zero());
395        stream.extend(input_padded.write());
396        stream.extend(self.output_buffer.len().write());
397        let mut output_padded = self.output_buffer.to_vec();
398        output_padded.resize(PERMUTATION_WIDTH, InnerVal::zero());
399        stream.extend(output_padded.write());
400        stream
401    }
402}
403
404impl<
405        'a,
406        SC: StarkGenericConfig<
407            Pcs = <BabyBearPoseidon2 as StarkGenericConfig>::Pcs,
408            Challenge = <BabyBearPoseidon2 as StarkGenericConfig>::Challenge,
409            Challenger = <BabyBearPoseidon2 as StarkGenericConfig>::Challenger,
410        >,
411        A: MachineAir<SC::Val>,
412    > Hintable<C> for VerifyingKeyHint<'a, SC, A>
413{
414    type HintVariable = VerifyingKeyVariable<C>;
415
416    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
417        let commitment = InnerDigest::read(builder);
418        let pc_start = InnerVal::read(builder);
419        let preprocessed_sorted_idxs = Vec::<usize>::read(builder);
420        let prep_domains = Vec::<TwoAdicMultiplicativeCoset<InnerVal>>::read(builder);
421        VerifyingKeyVariable { commitment, pc_start, preprocessed_sorted_idxs, prep_domains }
422    }
423
424    fn write(&self) -> Vec<Vec<Block<<C as Config>::F>>> {
425        let (preprocessed_sorted_idxs, prep_domains) = get_preprocessed_data(self.machine, self.vk);
426
427        let mut stream = Vec::new();
428        let h: InnerDigest = self.vk.commit.into();
429        stream.extend(h.write());
430        stream.extend(self.vk.pc_start.write());
431        stream.extend(preprocessed_sorted_idxs.write());
432        stream.extend(prep_domains.write());
433        stream
434    }
435}
436
437// Implement Hintable<C> for ShardProof where SC is equivalent to BabyBearPoseidon2
438impl<
439        'a,
440        SC: StarkGenericConfig<
441            Pcs = <BabyBearPoseidon2 as StarkGenericConfig>::Pcs,
442            Challenge = <BabyBearPoseidon2 as StarkGenericConfig>::Challenge,
443            Challenger = <BabyBearPoseidon2 as StarkGenericConfig>::Challenger,
444        >,
445        A: MachineAir<SC::Val>,
446    > Hintable<C> for ShardProofHint<'a, SC, A>
447where
448    ShardCommitment<Com<SC>>: Hintable<C>,
449{
450    type HintVariable = ShardProofVariable<C>;
451
452    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
453        let commitment = ShardCommitment::read(builder);
454        let opened_values = ShardOpenedValues::read(builder);
455        let opening_proof = InnerPcsProof::read(builder);
456        let public_values = Vec::<InnerVal>::read(builder);
457        let quotient_data = Vec::<QuotientDataValues>::read(builder);
458        let sorted_idxs = Vec::<usize>::read(builder);
459        ShardProofVariable {
460            commitment,
461            opened_values,
462            opening_proof,
463            public_values,
464            quotient_data,
465            sorted_idxs,
466        }
467    }
468
469    fn write(&self) -> Vec<Vec<Block<<C as Config>::F>>> {
470        let quotient_data = get_chip_quotient_data(self.machine, self.proof);
471        let sorted_indices = get_sorted_indices(self.machine, self.proof);
472
473        [
474            self.proof.commitment.write(),
475            self.proof.opened_values.write(),
476            self.proof.opening_proof.write(),
477            self.proof.public_values.write(),
478            quotient_data.write(),
479            sorted_indices.write(),
480        ]
481        .concat()
482    }
483}
484
485impl<'a, A: MachineAir<BabyBear>> Hintable<C>
486    for SP1RecursionMemoryLayout<'a, BabyBearPoseidon2, A>
487{
488    type HintVariable = SP1RecursionMemoryLayoutVariable<C>;
489
490    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
491        let vk = VerifyingKeyHint::<'a, BabyBearPoseidon2, A>::read(builder);
492        let shard_proofs = Vec::<ShardProofHint<'a, BabyBearPoseidon2, A>>::read(builder);
493        let leaf_challenger = DuplexChallenger::<InnerVal, InnerPerm, 16, 8>::read(builder);
494        let initial_reconstruct_challenger =
495            DuplexChallenger::<InnerVal, InnerPerm, 16, 8>::read(builder);
496        let is_complete = builder.hint_var();
497
498        SP1RecursionMemoryLayoutVariable {
499            vk,
500            shard_proofs,
501            leaf_challenger,
502            initial_reconstruct_challenger,
503            is_complete,
504        }
505    }
506
507    fn write(&self) -> Vec<Vec<Block<<C as Config>::F>>> {
508        let mut stream = Vec::new();
509
510        let vk_hint = VerifyingKeyHint::<'a, BabyBearPoseidon2, _>::new(self.machine, self.vk);
511
512        let proof_hints = self
513            .shard_proofs
514            .iter()
515            .map(|proof| ShardProofHint::<BabyBearPoseidon2, A>::new(self.machine, proof))
516            .collect::<Vec<_>>();
517
518        stream.extend(vk_hint.write());
519        stream.extend(proof_hints.write());
520        stream.extend(self.leaf_challenger.write());
521        stream.extend(self.initial_reconstruct_challenger.write());
522        stream.extend((self.is_complete as usize).write());
523
524        stream
525    }
526}
527
528impl<'a, A: MachineAir<BabyBear>> Hintable<C>
529    for SP1CompressMemoryLayout<'a, BabyBearPoseidon2, A>
530{
531    type HintVariable = SP1CompressMemoryLayoutVariable<C>;
532
533    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
534        let compress_vk = VerifyingKeyHint::<'a, BabyBearPoseidon2, A>::read(builder);
535        let shard_proofs = Vec::<ShardProofHint<'a, BabyBearPoseidon2, A>>::read(builder);
536        let kinds = Vec::<usize>::read(builder);
537        let is_complete = builder.hint_var();
538
539        SP1CompressMemoryLayoutVariable { compress_vk, shard_proofs, kinds, is_complete }
540    }
541
542    fn write(&self) -> Vec<Vec<Block<<C as Config>::F>>> {
543        let mut stream = Vec::new();
544
545        let compress_vk_hint = VerifyingKeyHint::<'a, BabyBearPoseidon2, _>::new(
546            self.recursive_machine,
547            self.compress_vk,
548        );
549
550        let proof_hints = self
551            .shard_proofs
552            .iter()
553            .map(|proof| ShardProofHint::<BabyBearPoseidon2, A>::new(self.recursive_machine, proof))
554            .collect::<Vec<_>>();
555
556        let kinds = self.kinds.iter().map(|k| *k as usize).collect::<Vec<_>>();
557
558        stream.extend(compress_vk_hint.write());
559        stream.extend(proof_hints.write());
560        stream.extend(kinds.write());
561        stream.extend((self.is_complete as usize).write());
562
563        stream
564    }
565}
566
567impl<'a, A: MachineAir<BabyBear>> Hintable<C> for SP1RootMemoryLayout<'a, BabyBearPoseidon2, A> {
568    type HintVariable = SP1RootMemoryLayoutVariable<C>;
569
570    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
571        let proof = ShardProofHint::<'a, BabyBearPoseidon2, A>::read(builder);
572        let is_reduce = builder.hint_var();
573
574        SP1RootMemoryLayoutVariable { proof, is_reduce }
575    }
576
577    fn write(&self) -> Vec<Vec<Block<<C as Config>::F>>> {
578        let mut stream = Vec::new();
579
580        let proof_hint = ShardProofHint::<BabyBearPoseidon2, A>::new(self.machine, &self.proof);
581
582        stream.extend(proof_hint.write());
583        stream.extend((self.is_reduce as usize).write());
584
585        stream
586    }
587}
588
589impl<'a, A: MachineAir<BabyBear>> Hintable<C>
590    for SP1DeferredMemoryLayout<'a, BabyBearPoseidon2, A>
591{
592    type HintVariable = SP1DeferredMemoryLayoutVariable<C>;
593
594    fn read(builder: &mut Builder<C>) -> Self::HintVariable {
595        let compress_vk = VerifyingKeyHint::<'a, BabyBearPoseidon2, A>::read(builder);
596        let proofs = Vec::<ShardProofHint<'a, BabyBearPoseidon2, A>>::read(builder);
597        let start_reconstruct_deferred_digest = Vec::<BabyBear>::read(builder);
598        let is_complete = builder.hint_var();
599
600        let sp1_vk = VerifyingKeyHint::<'a, BabyBearPoseidon2, RiscvAir<_>>::read(builder);
601        let committed_value_digest = Vec::<Vec<InnerVal>>::read(builder);
602        let deferred_proofs_digest = Vec::<InnerVal>::read(builder);
603        let leaf_challenger = DuplexChallenger::<InnerVal, InnerPerm, 16, 8>::read(builder);
604        let end_pc = InnerVal::read(builder);
605        let end_shard = InnerVal::read(builder);
606        let end_execution_shard = InnerVal::read(builder);
607        let init_addr_bits = Vec::<InnerVal>::read(builder);
608        let finalize_addr_bits = Vec::<InnerVal>::read(builder);
609
610        SP1DeferredMemoryLayoutVariable {
611            compress_vk,
612            proofs,
613            start_reconstruct_deferred_digest,
614            is_complete,
615            sp1_vk,
616            committed_value_digest,
617            deferred_proofs_digest,
618            leaf_challenger,
619            end_pc,
620            end_shard,
621            end_execution_shard,
622            init_addr_bits,
623            finalize_addr_bits,
624        }
625    }
626
627    fn write(&self) -> Vec<Vec<Block<<C as Config>::F>>> {
628        let mut stream = Vec::new();
629
630        let sp1_vk_hint =
631            VerifyingKeyHint::<'a, BabyBearPoseidon2, _>::new(self.sp1_machine, self.sp1_vk);
632
633        let compress_vk_hint =
634            VerifyingKeyHint::<'a, BabyBearPoseidon2, _>::new(self.machine, self.compress_vk);
635
636        let proof_hints = self
637            .proofs
638            .iter()
639            .map(|proof| ShardProofHint::<BabyBearPoseidon2, A>::new(self.machine, proof))
640            .collect::<Vec<_>>();
641
642        let committed_value_digest =
643            self.committed_value_digest.iter().map(|w| w.0.to_vec()).collect::<Vec<_>>();
644
645        stream.extend(compress_vk_hint.write());
646        stream.extend(proof_hints.write());
647        stream.extend(self.start_reconstruct_deferred_digest.write());
648        stream.extend((self.is_complete as usize).write());
649
650        stream.extend(sp1_vk_hint.write());
651        stream.extend(committed_value_digest.write());
652        stream.extend(self.deferred_proofs_digest.write());
653        stream.extend(self.leaf_challenger.write());
654        stream.extend(self.end_pc.write());
655        stream.extend(self.end_shard.write());
656        stream.extend(self.end_execution_shard.write());
657        stream.extend(self.init_addr_bits.to_vec().write());
658        stream.extend(self.finalize_addr_bits.to_vec().write());
659
660        stream
661    }
662}