openvm_sdk/keygen/
dummy.rs

1use std::sync::Arc;
2
3use openvm_circuit::{
4    arch::{
5        instructions::{
6            exe::VmExe, instruction::Instruction, program::Program, LocalOpcode,
7            SystemOpcode::TERMINATE,
8        },
9        ContinuationVmProof, SingleSegmentVmExecutor, VirtualMachine, VmComplexTraceHeights,
10        VmConfig, VmExecutor,
11    },
12    system::program::trace::VmCommittedExe,
13    utils::next_power_of_two_or_zero,
14};
15use openvm_continuations::verifier::{
16    internal::types::InternalVmVerifierInput,
17    leaf::{types::LeafVmVerifierInput, LeafVmVerifierConfig},
18    root::types::RootVmVerifierInput,
19};
20use openvm_native_circuit::NativeConfig;
21use openvm_native_compiler::ir::DIGEST_SIZE;
22use openvm_native_recursion::hints::Hintable;
23use openvm_rv32im_circuit::Rv32ImConfig;
24use openvm_stark_sdk::{
25    config::{
26        baby_bear_poseidon2::BabyBearPoseidon2Engine,
27        fri_params::standard_fri_params_with_100_bits_conjectured_security, FriParameters,
28    },
29    engine::StarkFriEngine,
30    openvm_stark_backend::{
31        config::StarkGenericConfig, p3_field::FieldAlgebra, proof::Proof, Chip,
32    },
33};
34
35use crate::{
36    prover::vm::{
37        local::VmLocalProver, types::VmProvingKey, ContinuationVmProver, SingleSegmentVmProver,
38    },
39    NonRootCommittedExe, F, SC,
40};
41
42/// Returns:
43/// - trace heights ordered by AIR ID
44/// - internal ordering of trace heights.
45///
46/// All trace heights are rounded to the next power of two (or 0 -> 0).
47pub(super) fn compute_root_proof_heights(
48    root_vm_config: NativeConfig,
49    root_exe: VmExe<F>,
50    dummy_internal_proof: &Proof<SC>,
51) -> (Vec<usize>, VmComplexTraceHeights) {
52    let num_user_public_values = root_vm_config.system.num_public_values - 2 * DIGEST_SIZE;
53    let root_input = RootVmVerifierInput {
54        proofs: vec![dummy_internal_proof.clone()],
55        public_values: vec![F::ZERO; num_user_public_values],
56    };
57    let vm = SingleSegmentVmExecutor::new(root_vm_config);
58    let res = vm
59        .execute_and_compute_heights(root_exe, root_input.write())
60        .unwrap();
61    let air_heights: Vec<_> = res
62        .air_heights
63        .into_iter()
64        .map(next_power_of_two_or_zero)
65        .collect();
66    let mut vm_heights = res.vm_heights;
67    vm_heights.round_to_next_power_of_two_or_zero();
68    (air_heights, vm_heights)
69}
70
71pub(super) fn dummy_internal_proof(
72    internal_vm_pk: Arc<VmProvingKey<SC, NativeConfig>>,
73    internal_exe: Arc<NonRootCommittedExe>,
74    leaf_proof: Proof<SC>,
75) -> Proof<SC> {
76    let mut internal_inputs = InternalVmVerifierInput::chunk_leaf_or_internal_proofs(
77        internal_exe.get_program_commit().into(),
78        &[leaf_proof],
79        1,
80    );
81    let internal_input = internal_inputs.pop().unwrap();
82    let internal_prover = VmLocalProver::<SC, NativeConfig, BabyBearPoseidon2Engine>::new(
83        internal_vm_pk,
84        internal_exe,
85    );
86    SingleSegmentVmProver::prove(&internal_prover, internal_input.write())
87}
88
89pub(super) fn dummy_internal_proof_riscv_app_vm(
90    leaf_vm_pk: Arc<VmProvingKey<SC, NativeConfig>>,
91    internal_vm_pk: Arc<VmProvingKey<SC, NativeConfig>>,
92    internal_exe: Arc<NonRootCommittedExe>,
93    num_public_values: usize,
94) -> Proof<SC> {
95    let fri_params = standard_fri_params_with_100_bits_conjectured_security(1);
96    let leaf_proof = dummy_leaf_proof_riscv_app_vm(leaf_vm_pk, num_public_values, fri_params);
97    dummy_internal_proof(internal_vm_pk, internal_exe, leaf_proof)
98}
99
100#[allow(dead_code)]
101pub fn dummy_leaf_proof<VC: VmConfig<F>>(
102    leaf_vm_pk: Arc<VmProvingKey<SC, NativeConfig>>,
103    app_vm_pk: Arc<VmProvingKey<SC, VC>>,
104    overridden_heights: Option<VmComplexTraceHeights>,
105) -> Proof<SC>
106where
107    VC::Executor: Chip<SC>,
108    VC::Periphery: Chip<SC>,
109{
110    let app_proof = dummy_app_proof_impl(app_vm_pk.clone(), overridden_heights);
111    dummy_leaf_proof_impl(leaf_vm_pk, app_vm_pk, &app_proof)
112}
113
114pub(super) fn dummy_leaf_proof_riscv_app_vm(
115    leaf_vm_pk: Arc<VmProvingKey<SC, NativeConfig>>,
116    num_public_values: usize,
117    app_fri_params: FriParameters,
118) -> Proof<SC> {
119    let app_vm_pk = Arc::new(dummy_riscv_app_vm_pk(num_public_values, app_fri_params));
120    let app_proof = dummy_app_proof_impl(app_vm_pk.clone(), None);
121    dummy_leaf_proof_impl(leaf_vm_pk, app_vm_pk, &app_proof)
122}
123
124fn dummy_leaf_proof_impl<VC: VmConfig<F>>(
125    leaf_vm_pk: Arc<VmProvingKey<SC, NativeConfig>>,
126    app_vm_pk: Arc<VmProvingKey<SC, VC>>,
127    app_proof: &ContinuationVmProof<SC>,
128) -> Proof<SC> {
129    let leaf_program = LeafVmVerifierConfig {
130        app_fri_params: app_vm_pk.fri_params,
131        app_system_config: app_vm_pk.vm_config.system().clone(),
132        compiler_options: Default::default(),
133    }
134    .build_program(&app_vm_pk.vm_pk.get_vk());
135    assert_eq!(
136        app_proof.per_segment.len(),
137        1,
138        "Dummy proof should only have 1 segment"
139    );
140    let e = BabyBearPoseidon2Engine::new(leaf_vm_pk.fri_params);
141    let leaf_exe = Arc::new(VmCommittedExe::<SC>::commit(
142        leaf_program.into(),
143        e.config.pcs(),
144    ));
145    let leaf_prover =
146        VmLocalProver::<SC, NativeConfig, BabyBearPoseidon2Engine>::new(leaf_vm_pk, leaf_exe);
147    let mut leaf_inputs = LeafVmVerifierInput::chunk_continuation_vm_proof(app_proof, 1);
148    let leaf_input = leaf_inputs.pop().unwrap();
149    SingleSegmentVmProver::prove(&leaf_prover, leaf_input.write_to_stream())
150}
151
152fn dummy_riscv_app_vm_pk(
153    num_public_values: usize,
154    fri_params: FriParameters,
155) -> VmProvingKey<SC, Rv32ImConfig> {
156    let vm_config = Rv32ImConfig::with_public_values(num_public_values);
157    let vm = VirtualMachine::new(BabyBearPoseidon2Engine::new(fri_params), vm_config.clone());
158    let vm_pk = vm.keygen();
159    VmProvingKey {
160        fri_params,
161        vm_config,
162        vm_pk,
163    }
164}
165
166fn dummy_app_proof_impl<VC: VmConfig<F>>(
167    app_vm_pk: Arc<VmProvingKey<SC, VC>>,
168    overridden_heights: Option<VmComplexTraceHeights>,
169) -> ContinuationVmProof<SC>
170where
171    VC::Executor: Chip<SC>,
172    VC::Periphery: Chip<SC>,
173{
174    let fri_params = app_vm_pk.fri_params;
175    let dummy_exe = dummy_app_committed_exe(fri_params);
176    // Enforce each AIR to have at least 1 row.
177    let overridden_heights = if let Some(overridden_heights) = overridden_heights {
178        overridden_heights
179    } else {
180        // We first execute once to get the trace heights from dummy_exe, then pad to powers of 2 (forcing trace height 0 to 1)
181        let executor = VmExecutor::new(app_vm_pk.vm_config.clone());
182        let mut results = executor
183            .execute_segments(dummy_exe.exe.clone(), vec![])
184            .unwrap();
185        // ASSUMPTION: the dummy exe has only 1 segment
186        assert_eq!(results.len(), 1, "dummy exe should have only 1 segment");
187        let mut result = results.pop().unwrap();
188        result.chip_complex.finalize_memory();
189        let mut vm_heights = result.chip_complex.get_internal_trace_heights();
190        vm_heights.round_to_next_power_of_two();
191        vm_heights
192    };
193    // For the dummy proof, we must override the trace heights.
194    let app_prover =
195        VmLocalProver::<SC, VC, BabyBearPoseidon2Engine>::new_with_overridden_trace_heights(
196            app_vm_pk,
197            dummy_exe,
198            Some(overridden_heights),
199        );
200    ContinuationVmProver::prove(&app_prover, vec![])
201}
202
203fn dummy_app_committed_exe(fri_params: FriParameters) -> Arc<NonRootCommittedExe> {
204    let program = dummy_app_program();
205    let e = BabyBearPoseidon2Engine::new(fri_params);
206    Arc::new(VmCommittedExe::<SC>::commit(program.into(), e.config.pcs()))
207}
208
209fn dummy_app_program() -> Program<F> {
210    let mut ret = Program::from_instructions(&[Instruction::from_isize(
211        TERMINATE.global_opcode(),
212        0,
213        0,
214        0,
215        0,
216        0,
217    )]);
218    ret.max_num_public_values = 0;
219    ret
220}