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
23pub 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#[derive(Debug)]
36pub struct TraceProvingInputs {
37 trace_inputs: TraceBuildInputs,
38 options: ProvingOptions,
39}
40
41impl TraceProvingInputs {
42 pub fn new(trace_inputs: TraceBuildInputs, options: ProvingOptions) -> Self {
44 Self { trace_inputs, options }
45 }
46
47 pub fn into_parts(self) -> (TraceBuildInputs, ProvingOptions) {
49 (self.trace_inputs, self.options)
50 }
51}
52
53#[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 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#[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#[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}
168pub 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 let proof_bytes = bincode::serialize(&output.proof)
201 .map_err(|e| ExecutionError::ProvingError(e.to_string()))?;
202 Ok(proof_bytes)
203}