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}