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::{
12 Felt, WORD_SIZE,
13 field::QuadFelt,
14 utils::{Matrix, RowMajorMatrix},
15};
16use miden_crypto::stark::{
17 StarkConfig, air::VarLenPublicInputs, challenger::CanObserve, lmcs::Lmcs, proof::StarkOutput,
18};
19use miden_processor::{
20 FastProcessor, Program,
21 trace::{AuxTraceBuilders, ExecutionTrace, build_trace},
22};
23use tracing::instrument;
24
25mod proving_options;
26
27pub use miden_air::{DeserializationError, ProcessorAir, PublicInputs, config};
30pub use miden_core::proof::{ExecutionProof, HashFunction};
31pub use miden_processor::{
32 ExecutionError, ExecutionOptions, ExecutionOutput, FutureMaybeSend, Host, InputError,
33 ProgramInfo, StackInputs, StackOutputs, SyncHost, TraceBuildInputs, TraceGenerationContext,
34 Word, advice::AdviceInputs, crypto, field, serde, utils,
35};
36pub use proving_options::ProvingOptions;
37
38#[derive(Debug)]
40pub struct TraceProvingInputs {
41 trace_inputs: TraceBuildInputs,
42 options: ProvingOptions,
43}
44
45impl TraceProvingInputs {
46 pub fn new(trace_inputs: TraceBuildInputs, options: ProvingOptions) -> Self {
48 Self { trace_inputs, options }
49 }
50
51 pub fn into_parts(self) -> (TraceBuildInputs, ProvingOptions) {
53 (self.trace_inputs, self.options)
54 }
55}
56
57#[instrument("prove_program", skip_all)]
73pub async fn prove(
74 program: &Program,
75 stack_inputs: StackInputs,
76 advice_inputs: AdviceInputs,
77 host: &mut impl Host,
78 execution_options: ExecutionOptions,
79 proving_options: ProvingOptions,
80) -> Result<(StackOutputs, ExecutionProof), ExecutionError> {
81 let processor = FastProcessor::new_with_options(stack_inputs, advice_inputs, execution_options);
83
84 let trace_inputs = processor.execute_trace_inputs(program, host).await?;
85 prove_from_trace_sync(TraceProvingInputs::new(trace_inputs, proving_options))
86}
87
88#[instrument("prove_program_sync", skip_all)]
90pub fn prove_sync(
91 program: &Program,
92 stack_inputs: StackInputs,
93 advice_inputs: AdviceInputs,
94 host: &mut impl SyncHost,
95 execution_options: ExecutionOptions,
96 proving_options: ProvingOptions,
97) -> Result<(StackOutputs, ExecutionProof), ExecutionError> {
98 let processor = FastProcessor::new_with_options(stack_inputs, advice_inputs, execution_options);
99
100 let trace_inputs = processor.execute_trace_inputs_sync(program, host)?;
101 prove_from_trace_sync(TraceProvingInputs::new(trace_inputs, proving_options))
102}
103
104#[instrument("prove_trace_sync", skip_all)]
110pub fn prove_from_trace_sync(
111 inputs: TraceProvingInputs,
112) -> Result<(StackOutputs, ExecutionProof), ExecutionError> {
113 let (trace_inputs, options) = inputs.into_parts();
114 let trace = build_trace(trace_inputs)?;
115 prove_execution_trace(trace, options)
116}
117
118fn prove_execution_trace(
119 trace: ExecutionTrace,
120 options: ProvingOptions,
121) -> Result<(StackOutputs, ExecutionProof), ExecutionError> {
122 tracing::event!(
123 tracing::Level::INFO,
124 "Generated execution trace of {} columns and {} steps (padded from {})",
125 miden_air::trace::TRACE_WIDTH,
126 trace.trace_len_summary().padded_trace_len(),
127 trace.trace_len_summary().trace_len()
128 );
129
130 let stack_outputs = *trace.stack_outputs();
131 let precompile_requests = trace.precompile_requests().to_vec();
132 let hash_fn = options.hash_fn();
133
134 let trace_matrix = {
135 let _span = tracing::info_span!("to_row_major_matrix").entered();
136 trace.to_row_major_matrix()
137 };
138
139 let (public_values, kernel_felts) = trace.public_inputs().to_air_inputs();
140 let var_len_public_inputs: &[&[Felt]] = &[&kernel_felts];
141 let aux_builder = trace.aux_trace_builders();
142
143 let params = config::pcs_params();
144 let proof_bytes = match hash_fn {
145 HashFunction::Blake3_256 => {
146 let config = config::blake3_256_config(params);
147 prove_stark(&config, &trace_matrix, &public_values, var_len_public_inputs, &aux_builder)
148 },
149 HashFunction::Keccak => {
150 let config = config::keccak_config(params);
151 prove_stark(&config, &trace_matrix, &public_values, var_len_public_inputs, &aux_builder)
152 },
153 HashFunction::Rpo256 => {
154 let config = config::rpo_config(params);
155 prove_stark(&config, &trace_matrix, &public_values, var_len_public_inputs, &aux_builder)
156 },
157 HashFunction::Poseidon2 => {
158 let config = config::poseidon2_config(params);
159 prove_stark(&config, &trace_matrix, &public_values, var_len_public_inputs, &aux_builder)
160 },
161 HashFunction::Rpx256 => {
162 let config = config::rpx_config(params);
163 prove_stark(&config, &trace_matrix, &public_values, var_len_public_inputs, &aux_builder)
164 },
165 }?;
166
167 let proof = ExecutionProof::new(proof_bytes, hash_fn, precompile_requests);
168
169 Ok((stack_outputs, proof))
170}
171
172pub fn prove_stark<SC>(
180 config: &SC,
181 trace: &RowMajorMatrix<Felt>,
182 public_values: &[Felt],
183 var_len_public_inputs: VarLenPublicInputs<'_, Felt>,
184 aux_builder: &AuxTraceBuilders,
185) -> Result<Vec<u8>, ExecutionError>
186where
187 SC: StarkConfig<Felt, QuadFelt>,
188 <SC::Lmcs as Lmcs>::Commitment: Serialize,
189{
190 let log_trace_height = trace.height().ilog2() as u8;
191
192 let mut challenger = config.challenger();
193 config::observe_protocol_params(&mut challenger, log_trace_height as u64);
194 challenger.observe_slice(public_values);
195 config::observe_var_len_public_inputs(&mut challenger, var_len_public_inputs, &[WORD_SIZE]);
196 let output: StarkOutput<Felt, QuadFelt, SC> = miden_crypto::stark::prover::prove_single(
197 config,
198 &ProcessorAir,
199 trace,
200 public_values,
201 var_len_public_inputs,
202 aux_builder,
203 challenger,
204 )
205 .map_err(|e| ExecutionError::ProvingError(e.to_string()))?;
206 let proof_bytes = bincode::serialize(&(log_trace_height, &output.proof))
210 .map_err(|e| ExecutionError::ProvingError(e.to_string()))?;
211 Ok(proof_bytes)
212}