Skip to main content

miden_protocol/block/
kernel.rs

1use alloc::vec::Vec;
2
3use miden_core::program::KernelDescriptor;
4
5use crate::block::ProposedBlock;
6use crate::crypto::SequentialCommit;
7use crate::utils::serde::Deserializable;
8use crate::utils::sync::LazyLock;
9use crate::vm::{AdviceInputs, Package, Program, ProgramInfo, StackInputs};
10use crate::{Felt, Word};
11
12// CONSTANTS
13// ================================================================================================
14
15static KERNEL_MAIN: LazyLock<Program> = LazyLock::new(|| {
16    let bytes = include_bytes!(concat!(
17        env!("OUT_DIR"),
18        "/assets/kernels/miden-block-kernel:miden-block-kernel.masp"
19    ));
20    Package::read_from_bytes(bytes)
21        .expect("failed to deserialize block kernel package")
22        .try_into_program()
23        .expect("block kernel package should contain a program")
24});
25
26// BLOCK KERNEL
27// ================================================================================================
28
29/// The block kernel program: an executable Miden program that proves a block of batches.
30///
31/// The kernel takes `[PREV_BLOCK_COMMITMENT, BATCHES_COMMITMENT]` as public inputs and emits
32/// `[BLOCK_COMMITMENT, NULLIFIER_COMMITMENT]`. See `asm/kernels/block/main.masm` for the
33/// input/output contract.
34pub struct BlockKernel;
35
36impl BlockKernel {
37    // KERNEL SOURCE CODE
38    // --------------------------------------------------------------------------------------------
39
40    /// Returns the executable block kernel program loaded from the build's `OUT_DIR`.
41    pub fn main() -> Program {
42        KERNEL_MAIN.clone()
43    }
44
45    /// Returns [`ProgramInfo`] for the block kernel program.
46    ///
47    /// The block kernel does not expose syscalls, so the associated [`KernelDescriptor`] is empty.
48    pub fn program_info() -> ProgramInfo {
49        ProgramInfo::new(Self::main().hash(), KernelDescriptor::default())
50    }
51
52    // INPUT BUILDERS
53    // --------------------------------------------------------------------------------------------
54
55    /// Transforms the provided [`ProposedBlock`] into the stack and advice inputs needed to execute
56    /// the block kernel.
57    pub fn prepare_inputs(proposed_block: &ProposedBlock) -> (StackInputs, AdviceInputs) {
58        let prev_block_commitment = proposed_block.prev_block_header().commitment();
59        let batches_commitment = proposed_block.batches().to_commitment();
60
61        let stack_inputs = Self::build_input_stack(prev_block_commitment, batches_commitment);
62
63        // TODO: Create a dedicated `BlockAdviceInputs` struct mirroring `TransactionAdviceInputs`
64        let advice_inputs = AdviceInputs::default();
65
66        (stack_inputs, advice_inputs)
67    }
68
69    /// Returns the stack with the public inputs required by the block kernel.
70    ///
71    /// The initial stack is:
72    ///
73    /// ```text
74    /// [PREV_BLOCK_COMMITMENT, BATCHES_COMMITMENT, pad(8)]
75    /// ```
76    ///
77    /// Where:
78    /// - `PREV_BLOCK_COMMITMENT` is the commitment of the block header this block builds on top of.
79    /// - `BATCHES_COMMITMENT` is the sequential commitment to the batch IDs in the block.
80    pub fn build_input_stack(prev_block_commitment: Word, batches_commitment: Word) -> StackInputs {
81        let mut inputs: Vec<Felt> = Vec::with_capacity(8);
82        inputs.extend_from_slice(prev_block_commitment.as_elements());
83        inputs.extend_from_slice(batches_commitment.as_elements());
84
85        StackInputs::new(&inputs).expect("number of stack inputs should be <= 16")
86    }
87}