Skip to main content

miden_prover/
lib.rs

1#![no_std]
2
3extern crate alloc;
4
5#[cfg(feature = "std")]
6extern crate std;
7
8use alloc::{string::ToString, vec::Vec};
9
10use ::serde::Serialize;
11use miden_core::{Felt, WORD_SIZE, field::QuadFelt, utils::RowMajorMatrix};
12use miden_crypto::stark::{
13    StarkConfig, air::VarLenPublicInputs, challenger::CanObserve, lmcs::Lmcs, proof::StarkOutput,
14};
15use miden_processor::{
16    FastProcessor, Program,
17    trace::{ExecutionTrace, build_trace},
18};
19use tracing::instrument;
20
21mod proving_options;
22
23// EXPORTS
24// ================================================================================================
25pub use miden_air::{DeserializationError, ProcessorAir, PublicInputs, config};
26pub use miden_core::proof::{ExecutionProof, HashFunction};
27pub use miden_processor::{
28    ExecutionError, ExecutionOptions, ExecutionOutput, FutureMaybeSend, Host, InputError,
29    ProgramInfo, StackInputs, StackOutputs, SyncHost, TraceBuildInputs, TraceGenerationContext,
30    Word, advice::AdviceInputs, crypto, field, serde, utils,
31};
32pub use proving_options::ProvingOptions;
33
34/// Inputs required to prove from pre-executed trace data.
35#[derive(Debug)]
36pub struct TraceProvingInputs {
37    trace_inputs: TraceBuildInputs,
38    options: ProvingOptions,
39}
40
41impl TraceProvingInputs {
42    /// Creates a new bundle of post-execution trace inputs and proof-generation options.
43    pub fn new(trace_inputs: TraceBuildInputs, options: ProvingOptions) -> Self {
44        Self { trace_inputs, options }
45    }
46
47    /// Consumes this bundle and returns its trace inputs and proof-generation options.
48    pub fn into_parts(self) -> (TraceBuildInputs, ProvingOptions) {
49        (self.trace_inputs, self.options)
50    }
51}
52
53// PROVER
54// ================================================================================================
55
56/// Executes and proves the specified `program` and returns the result together with a STARK-based
57/// proof of the program's execution.
58///
59/// - `stack_inputs` specifies the initial state of the stack for the VM.
60/// - `advice_inputs` provides the initial nondeterministic inputs for the VM.
61/// - `host` specifies the host environment which contain non-deterministic (secret) inputs for the
62///   prover.
63/// - `execution_options` defines VM execution parameters such as cycle limits and fragmentation.
64/// - `proving_options` defines parameters for STARK proof generation.
65///
66/// # Errors
67/// Returns an error if program execution or STARK proof generation fails for any reason.
68#[instrument("prove_program", skip_all)]
69pub async fn prove(
70    program: &Program,
71    stack_inputs: StackInputs,
72    advice_inputs: AdviceInputs,
73    host: &mut impl Host,
74    execution_options: ExecutionOptions,
75    proving_options: ProvingOptions,
76) -> Result<(StackOutputs, ExecutionProof), ExecutionError> {
77    // execute the program to create an execution trace using FastProcessor
78    let processor = FastProcessor::new_with_options(stack_inputs, advice_inputs, execution_options)
79        .map_err(ExecutionError::advice_error_no_context)?;
80
81    let trace_inputs = processor.execute_trace_inputs(program, host).await?;
82    prove_from_trace_sync(TraceProvingInputs::new(trace_inputs, proving_options))
83}
84
85/// Synchronous wrapper for [`prove()`].
86#[instrument("prove_program_sync", skip_all)]
87pub fn prove_sync(
88    program: &Program,
89    stack_inputs: StackInputs,
90    advice_inputs: AdviceInputs,
91    host: &mut impl SyncHost,
92    execution_options: ExecutionOptions,
93    proving_options: ProvingOptions,
94) -> Result<(StackOutputs, ExecutionProof), ExecutionError> {
95    let processor = FastProcessor::new_with_options(stack_inputs, advice_inputs, execution_options)
96        .map_err(ExecutionError::advice_error_no_context)?;
97
98    let trace_inputs = processor.execute_trace_inputs_sync(program, host)?;
99    prove_from_trace_sync(TraceProvingInputs::new(trace_inputs, proving_options))
100}
101
102/// Builds an execution trace from pre-executed trace inputs and proves it synchronously.
103///
104/// This is useful when program execution has already happened elsewhere and only trace building
105/// plus proof generation remain. The execution settings are already reflected in the supplied
106/// `TraceBuildInputs`, so only proof-generation options remain in this API.
107#[instrument("prove_trace_sync", skip_all)]
108pub fn prove_from_trace_sync(
109    inputs: TraceProvingInputs,
110) -> Result<(StackOutputs, ExecutionProof), ExecutionError> {
111    let (trace_inputs, options) = inputs.into_parts();
112    let trace = build_trace(trace_inputs)?;
113    prove_execution_trace(trace, options)
114}
115
116fn prove_execution_trace(
117    trace: ExecutionTrace,
118    options: ProvingOptions,
119) -> Result<(StackOutputs, ExecutionProof), ExecutionError> {
120    tracing::event!(
121        tracing::Level::INFO,
122        "Generated execution trace of {} columns and {} steps (padded from {})",
123        miden_air::trace::TRACE_WIDTH,
124        trace.trace_len_summary().padded_trace_len(),
125        trace.trace_len_summary().trace_len()
126    );
127
128    let stack_outputs = *trace.stack_outputs();
129    let precompile_requests = trace.precompile_requests().to_vec();
130    let hash_fn = options.hash_fn();
131
132    let trace_matrix = {
133        let _span = tracing::info_span!("to_row_major_matrix").entered();
134        trace.to_row_major_matrix()
135    };
136
137    let (public_values, kernel_felts) = trace.public_inputs().to_air_inputs();
138    let var_len_public_inputs: &[&[Felt]] = &[&kernel_felts];
139
140    let params = config::pcs_params();
141    let proof_bytes = match hash_fn {
142        HashFunction::Blake3_256 => {
143            let config = config::blake3_256_config(params);
144            prove_stark(&config, &trace_matrix, &public_values, var_len_public_inputs)
145        },
146        HashFunction::Keccak => {
147            let config = config::keccak_config(params);
148            prove_stark(&config, &trace_matrix, &public_values, var_len_public_inputs)
149        },
150        HashFunction::Rpo256 => {
151            let config = config::rpo_config(params);
152            prove_stark(&config, &trace_matrix, &public_values, var_len_public_inputs)
153        },
154        HashFunction::Poseidon2 => {
155            let config = config::poseidon2_config(params);
156            prove_stark(&config, &trace_matrix, &public_values, var_len_public_inputs)
157        },
158        HashFunction::Rpx256 => {
159            let config = config::rpx_config(params);
160            prove_stark(&config, &trace_matrix, &public_values, var_len_public_inputs)
161        },
162    }?;
163
164    let proof = ExecutionProof::new(proof_bytes, hash_fn, precompile_requests);
165
166    Ok((stack_outputs, proof))
167}
168// STARK PROOF GENERATION
169// ================================================================================================
170
171/// Generates a STARK proof for the given trace and public values.
172///
173/// Pre-seeds the challenger with `public_values`, then delegates to the lifted
174/// prover. Returns the serialized proof bytes.
175pub fn prove_stark<SC>(
176    config: &SC,
177    trace: &RowMajorMatrix<Felt>,
178    public_values: &[Felt],
179    var_len_public_inputs: VarLenPublicInputs<'_, Felt>,
180) -> Result<Vec<u8>, ExecutionError>
181where
182    SC: StarkConfig<Felt, QuadFelt>,
183    <SC::Lmcs as Lmcs>::Commitment: Serialize,
184{
185    let mut challenger = config.challenger();
186    config::observe_protocol_params(&mut challenger);
187    challenger.observe_slice(public_values);
188    config::observe_var_len_public_inputs(&mut challenger, var_len_public_inputs, &[WORD_SIZE]);
189    let output: StarkOutput<Felt, QuadFelt, SC> = miden_crypto::stark::prover::prove_single(
190        config,
191        &ProcessorAir,
192        trace,
193        public_values,
194        var_len_public_inputs,
195        &ProcessorAir,
196        challenger,
197    )
198    .map_err(|e| ExecutionError::ProvingError(e.to_string()))?;
199    // Proof serialization via bincode; see https://github.com/0xMiden/miden-vm/issues/2550.
200    let proof_bytes = bincode::serialize(&output.proof)
201        .map_err(|e| ExecutionError::ProvingError(e.to_string()))?;
202    Ok(proof_bytes)
203}