miden_protocol/batch/kernel.rs
1use alloc::vec::Vec;
2
3use miden_core::program::Kernel;
4
5use crate::batch::{BatchId, ProposedBatch};
6use crate::utils::serde::Deserializable;
7use crate::utils::sync::LazyLock;
8use crate::vm::{AdviceInputs, Package, Program, ProgramInfo, StackInputs};
9use crate::{Felt, Word};
10
11// CONSTANTS
12// ================================================================================================
13
14static KERNEL_MAIN: LazyLock<Program> = LazyLock::new(|| {
15 let bytes = include_bytes!(concat!(
16 env!("OUT_DIR"),
17 "/assets/kernels/miden-batch-kernel:miden-batch-kernel.masp"
18 ));
19 Package::read_from_bytes(bytes)
20 .expect("failed to deserialize batch kernel package")
21 .try_into_program()
22 .expect("batch kernel package should contain a program")
23});
24
25// BATCH KERNEL
26// ================================================================================================
27
28/// The batch kernel program: an executable Miden program that proves a batch of transactions.
29///
30/// The kernel takes `[BLOCK_COMMITMENT, BATCH_ID]` as public inputs and emits
31/// `[INPUT_NOTES_COMMITMENT, BATCH_NOTE_TREE_ROOT, batch_expiration_block_num]`. See
32/// `asm/kernels/batch/main.masm` for the input/output contract.
33pub struct BatchKernel;
34
35impl BatchKernel {
36 // KERNEL SOURCE CODE
37 // --------------------------------------------------------------------------------------------
38
39 /// Returns the executable batch kernel program loaded from the build's `OUT_DIR`.
40 pub fn main() -> Program {
41 KERNEL_MAIN.clone()
42 }
43
44 /// Returns [`ProgramInfo`] for the batch kernel program.
45 ///
46 /// The batch kernel does not expose syscalls, so the associated [`Kernel`] is empty.
47 pub fn program_info() -> ProgramInfo {
48 ProgramInfo::new(Self::main().hash(), Kernel::default())
49 }
50
51 // INPUT BUILDERS
52 // --------------------------------------------------------------------------------------------
53
54 /// Transforms the provided [`ProposedBatch`] into the stack and advice inputs needed to
55 /// execute the batch kernel.
56 pub fn prepare_inputs(proposed_batch: &ProposedBatch) -> (StackInputs, AdviceInputs) {
57 let block_commitment = proposed_batch.reference_block_header().commitment();
58 let batch_id = proposed_batch.id();
59
60 let stack_inputs = Self::build_input_stack(block_commitment, batch_id);
61 let advice_inputs = Self::build_advice_inputs(proposed_batch);
62
63 (stack_inputs, advice_inputs)
64 }
65
66 /// Returns the stack with the public inputs required by the batch kernel.
67 ///
68 /// The initial stack is:
69 ///
70 /// ```text
71 /// [BLOCK_COMMITMENT, BATCH_ID, pad(8)]
72 /// ```
73 ///
74 /// Where:
75 /// - `BLOCK_COMMITMENT` is the commitment of the batch's reference block.
76 /// - `BATCH_ID` is the batch's [`BatchId`].
77 pub fn build_input_stack(block_commitment: Word, batch_id: BatchId) -> StackInputs {
78 let mut inputs: Vec<Felt> = Vec::with_capacity(8);
79 inputs.extend_from_slice(block_commitment.as_elements());
80 inputs.extend_from_slice(batch_id.as_word().as_elements());
81
82 StackInputs::new(&inputs).expect("number of stack inputs should be <= 16")
83 }
84
85 // ADVICE BUILDER
86 // --------------------------------------------------------------------------------------------
87
88 /// Builds the advice inputs (map + stack) consumed by the batch kernel.
89 ///
90 /// The skeleton kernel ignores its advice inputs, so this returns the default empty value.
91 fn build_advice_inputs(_proposed_batch: &ProposedBatch) -> AdviceInputs {
92 AdviceInputs::default()
93 }
94}