sp1_recursion_program/machine/
root.rs1use std::borrow::Borrow;
2
3use p3_air::Air;
4use p3_baby_bear::BabyBear;
5use p3_commit::TwoAdicMultiplicativeCoset;
6use p3_field::{AbstractField, PrimeField32, TwoAdicField};
7use sp1_primitives::types::RecursionProgramType;
8use sp1_recursion_compiler::{
9 config::InnerConfig,
10 ir::{Builder, Config, Felt, Var},
11 prelude::DslVariable,
12};
13use sp1_recursion_core::{
14 air::{RecursionPublicValues, RECURSIVE_PROOF_NUM_PV_ELTS},
15 runtime::{RecursionProgram, DIGEST_SIZE},
16};
17
18use sp1_recursion_compiler::prelude::*;
19use sp1_stark::{
20 air::MachineAir, baby_bear_poseidon2::BabyBearPoseidon2, Com, ShardProof, StarkGenericConfig,
21 StarkMachine, StarkVerifyingKey,
22};
23
24use crate::{
25 challenger::{CanObserveVariable, DuplexChallengerVariable},
26 fri::TwoAdicFriPcsVariable,
27 hints::Hintable,
28 machine::utils::proof_data_from_vk,
29 stark::{RecursiveVerifierConstraintFolder, ShardProofHint, StarkVerifier},
30 types::ShardProofVariable,
31 utils::{const_fri_config, hash_vkey},
32};
33
34use super::utils::{commit_public_values, verify_public_values_hash};
35
36#[derive(Debug, Clone, Copy)]
38pub struct SP1RootVerifier<C: Config, SC: StarkGenericConfig, A> {
39 _phantom: std::marker::PhantomData<(C, SC, A)>,
40}
41
42pub struct SP1RootMemoryLayout<'a, SC: StarkGenericConfig, A: MachineAir<SC::Val>> {
43 pub machine: &'a StarkMachine<SC, A>,
44 pub proof: ShardProof<SC>,
45 pub is_reduce: bool,
46}
47
48#[derive(DslVariable, Clone)]
49pub struct SP1RootMemoryLayoutVariable<C: Config> {
50 pub proof: ShardProofVariable<C>,
51 pub is_reduce: Var<C::N>,
52}
53
54impl<A> SP1RootVerifier<InnerConfig, BabyBearPoseidon2, A>
55where
56 A: MachineAir<BabyBear> + for<'a> Air<RecursiveVerifierConstraintFolder<'a, InnerConfig>>,
57{
58 pub fn build(
60 machine: &StarkMachine<BabyBearPoseidon2, A>,
61 vk: &StarkVerifyingKey<BabyBearPoseidon2>,
62 program_type: RecursionProgramType,
63 ) -> RecursionProgram<BabyBear> {
64 assert!(matches!(program_type, RecursionProgramType::Shrink | RecursionProgramType::Wrap));
65
66 let mut builder = Builder::<InnerConfig>::new(program_type);
67
68 let proof: ShardProofVariable<_> = builder.uninit();
69 ShardProofHint::<BabyBearPoseidon2, A>::witness(&proof, &mut builder);
70
71 let pcs = TwoAdicFriPcsVariable {
72 config: const_fri_config(&mut builder, machine.config().pcs().fri_config()),
73 };
74
75 SP1RootVerifier::verify(&mut builder, &pcs, machine, vk, &proof);
76
77 builder.compile_program()
78 }
79}
80
81impl<C: Config, SC, A> SP1RootVerifier<C, SC, A>
82where
83 C::F: PrimeField32 + TwoAdicField,
84 SC: StarkGenericConfig<
85 Val = C::F,
86 Challenge = C::EF,
87 Domain = TwoAdicMultiplicativeCoset<C::F>,
88 >,
89 A: MachineAir<C::F> + for<'a> Air<RecursiveVerifierConstraintFolder<'a, C>>,
90 Com<SC>: Into<[SC::Val; DIGEST_SIZE]>,
91{
92 pub fn verify(
97 builder: &mut Builder<C>,
98 pcs: &TwoAdicFriPcsVariable<C>,
99 machine: &StarkMachine<SC, A>,
100 vk: &StarkVerifyingKey<SC>,
101 proof: &ShardProofVariable<C>,
102 ) {
103 let vk = proof_data_from_vk(builder, vk, machine);
105
106 let mut challenger = DuplexChallengerVariable::new(builder);
109 challenger.observe(builder, vk.commitment.clone());
111 challenger.observe(builder, vk.pc_start);
112 challenger.observe(builder, proof.commitment.main_commit.clone());
114 for j in 0..machine.num_pv_elts() {
115 let element = builder.get(&proof.public_values, j);
116 challenger.observe(builder, element);
117 }
118 StarkVerifier::<C, SC>::verify_shard(
120 builder,
121 &vk,
122 pcs,
123 machine,
124 &mut challenger,
125 proof,
126 true,
127 );
128
129 let public_values_elements = (0..RECURSIVE_PROOF_NUM_PV_ELTS)
131 .map(|i| builder.get(&proof.public_values, i))
132 .collect::<Vec<Felt<_>>>();
133 let public_values: &RecursionPublicValues<Felt<C::F>> =
134 public_values_elements.as_slice().borrow();
135
136 verify_public_values_hash(builder, public_values);
138
139 builder.assert_felt_eq(public_values.is_complete, C::F::one());
145
146 if matches!(builder.program_type, RecursionProgramType::Shrink) {
149 let vk_digest = hash_vkey(builder, &vk);
150 for (i, reduce_digest_elem) in public_values.compress_vk_digest.iter().enumerate() {
151 let vk_digest_elem = builder.get(&vk_digest, i);
152 builder.assert_felt_eq(vk_digest_elem, *reduce_digest_elem);
153 }
154 }
155
156 commit_public_values(builder, public_values);
157
158 builder.halt();
159 }
160}