Skip to main content

miden_core/deferred/
mod.rs

1//! Content-addressed deferred computation for VM hints.
2//!
3//! Deferred events let programs commit opaque statements during execution and leave their
4//! semantic checks to installed [`Precompile`]s. The framework stores those commitments as a DAG
5//! of [`Node`]s and a deferred root commitment that verifies by evaluating every logged statement
6//! to TRUE.
7//!
8//! `miden-core` owns the data model, registry, state, and wire validation; the processor only
9//! provides system-event plumbing.
10
11mod claim;
12mod node;
13mod precompile;
14mod precompile_registry;
15mod state;
16mod wire;
17mod witness;
18
19use alloc::boxed::Box;
20
21pub use claim::DeferredClaim;
22pub use node::{DataChunk, Digest, Node, NodeType, Payload, TRUE_DIGEST, Tag};
23pub use precompile::{Precompile, precompile_id};
24pub use precompile_registry::PrecompileRegistry;
25pub use state::{DeferredContext, DeferredState};
26pub use wire::{DeferredStateWire, IntegrityError};
27pub use witness::{PrecompileWitness, PrecompileWitnessError};
28
29use crate::Word;
30
31/// The deferred root committed in public inputs.
32pub type DeferredRoot = Digest;
33
34/// Fixed capacity word used to domain-separate deferred root folds.
35pub const DEFERRED_ROOT_DOMAIN: Word = Word::new(Tag::AND.as_word());
36
37/// Hard maximum approximate number of field elements allowed in deferred state.
38pub const MAX_DEFERRED_ELEMENTS: usize = 1 << 20;
39
40/// Hard library safety ceiling for ordered precompile roots.
41///
42/// This bounds root-vector allocation and aggregate-root folding.
43pub const MAX_PRECOMPILE_ROOTS: usize = 1 << 12;
44
45/// Folds a verified deferred statement into the rolling deferred root.
46pub fn fold_deferred_root(root: DeferredRoot, statement: Digest) -> DeferredRoot {
47    Node::and(root, statement).digest()
48}
49
50// ERROR
51// ================================================================================================
52
53/// Coarse deferred-framework failures shared by deferred state and precompile evaluation.
54#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
55pub enum DeferredError {
56    #[error("invalid or unknown deferred tag")]
57    InvalidTag,
58    #[error("referenced digest is not present in deferred state")]
59    MissingNode,
60    #[error("conflicting node definition for digest")]
61    ConflictingNode,
62    #[error("payload is not valid for the given tag")]
63    InvalidPayload,
64    #[error("equality assertion failed")]
65    AssertionFailed,
66    #[error("deferred insertion requires {num_elements} elements but only {max} remain")]
67    DeferredStateTooLarge { num_elements: usize, max: usize },
68    #[error("operation is not supported by this handler")]
69    Unsupported,
70    #[error("invalid deferred root transition: expected {expected:?}, got {actual:?}")]
71    InvalidDeferredRootTransition { expected: Digest, actual: Digest },
72}
73
74/// Errors produced while evaluating deferred nodes through precompiles.
75#[derive(Debug, Clone, thiserror::Error)]
76pub enum PrecompileError {
77    /// A referenced child digest is not present in `DeferredState.nodes`.
78    #[error("deferred DAG is missing a node referenced during evaluation")]
79    MissingNode,
80
81    /// A tag is unknown or its payload shape is invalid for the decoded node type.
82    #[error("node failed precompile validation")]
83    InvalidNode,
84
85    /// A precompile predicate evaluated to false.
86    #[error("deferred assertion failed: values disagree")]
87    AssertionFailed,
88
89    /// A framework-level error surfaced by a precompile evaluation.
90    #[error(transparent)]
91    Other(#[from] DeferredError),
92
93    /// Adds the owning precompile's name to a tag or evaluation failure.
94    ///
95    /// Registry construction errors are setup-time panics and are not represented here.
96    #[error("precompile `{name}`: {source}")]
97    Precompile {
98        name: &'static str,
99        source: Box<PrecompileError>,
100    },
101}
102
103impl PrecompileError {
104    /// Returns the underlying failure without registry attribution wrappers.
105    pub fn root(&self) -> &PrecompileError {
106        match self {
107            PrecompileError::Precompile { source, .. } => source.root(),
108            other => other,
109        }
110    }
111
112    pub(crate) fn with_precompile(name: &'static str, source: PrecompileError) -> Self {
113        Self::Precompile { name, source: Box::new(source) }
114    }
115}