Skip to main content

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}