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