Skip to content

Commit 6090d64

Browse files
authored
Merge pull request #2823 from 0xMiden/plafer-merge-audit-fixes-in-next
Merge audit fixes in next
2 parents eace5a1 + 047ff72 commit 6090d64

87 files changed

Lines changed: 3763 additions & 395 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/fuzz.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@ jobs:
3030
- mast_node_info
3131
- basic_block_data
3232
- debug_info
33+
- program_deserialize
34+
- kernel_deserialize
35+
- stack_io_deserialize
36+
- advice_inputs_deserialize
37+
- operation_deserialize
38+
- execution_proof_deserialize
39+
- precompile_request_deserialize
40+
- library_deserialize
41+
- package_deserialize
3342
timeout-minutes: 15
3443
steps:
3544
- uses: actions/checkout@v4

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,24 @@
1313
- Added optional tagging instrumentation for AIR constraints (test-only; enables stable ID tracking and OOD parity checks) ([#2713](https://github.com/0xMiden/miden-vm/pull/2713)).
1414
- Fix a possible panic in decorator serialization ([#2742](https://github.com/0xMiden/miden-vm/pull/2742)).
1515
- Added `math::u128` comparison (`lt`, `lte`, `gt`, `gte`), bitwise (`and`, `or`, `xor`, `not`), and shift (`shl`, `shr`, `rotl`, `rotr`) operations ([#2624](https://github.com/0xMiden/miden-vm/pull/2624)).
16+
- Added recursion guards for assembly inputs and tests ([#2792](https://github.com/0xMiden/miden-vm/pull/2792)).
1617
- [BREAKING] `Operation` enum now only encodes basic block operations ([#2771](https://github.com/0xMiden/miden-vm/pull/2771)).
1718
- Added `math::u128` division operations ([#2776](https://github.com/0xMiden/miden-vm/pull/2776)).
1819
- Introduced `build_trace_with_max_len()` which stops building the trace after a given max, and `build_trace()` no longer allocates more than 2^29 rows ([#2809](https://github.com/0xMiden/miden-vm/pull/2809)).
1920

2021
#### Fixes
2122

2223
- Fixed `Constant::PartialEq` to include `visibility` field in equality comparison, making it consistent with other exportable items (`Procedure`, `TypeAlias`, `EnumType`).
24+
- Cryptostream operation now correctly sends chiplets bus memory requests ([#2686](https://github.com/0xMiden/miden-vm/pull/2686)).
25+
- Hardened untrusted deserialization by enforcing budgets and depth limits, plus expanded fuzzing coverage ([#2777](https://github.com/0xMiden/miden-vm/pull/2777)).
26+
- Hardened AEAD decrypt size calculations ([#2789](https://github.com/0xMiden/miden-vm/pull/2789)).
27+
- `SystemEvent::HpermToMap` handler now computes the correct permutation ([#2801](https://github.com/0xMiden/miden-vm/pull/2801)).
28+
- Fixes an possible u64 overflow issue in `op_eval_circuit()` [#2799](https://github.com/0xMiden/miden-vm/pull/2799)
29+
- Preserved dynexec/dyncall distinction (and digests) when remapping or merging MAST forests ([#2784](https://github.com/0xMiden/miden-vm/pull/2784)).
30+
- Hardened MASM parsing and constants handling (lexer invalid-token spans, repeat count bounds, constant range checks, field division folding, and `push.WORD[...]` index validation) ([#2803](https://github.com/0xMiden/miden-vm/pull/2803)).
31+
- Introduced `FastProcessor` safe stack method accesses for event handlers ([#2797](https://github.com/0xMiden/miden-vm/pull/2797)).
32+
- Hardened syscall target validation to avoid panic paths and reject invalid digests at assembly time ([#2804](https://github.com/0xMiden/miden-vm/pull/2804)).
33+
- Add bounds to attacker-controlled allocation sizes in advice map and keccak256/sha512 precompiles ([#2805](https://github.com/0xMiden/miden-vm/pull/2805)).
2334
- `build_trace()` no longer panics when no core trace contexts are provided ([#2809](https://github.com/0xMiden/miden-vm/pull/2809)).
2435

2536
## 0.21.2 (2026-03-04)

Makefile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,15 @@ fuzz-mast-validate: ## Run fuzzing for UntrustedMastForest validation
258258
fuzz-all: ## Run all fuzz targets (in sequence)
259259
-@cargo +nightly fuzz run mast_forest_deserialize --release --fuzz-dir miden-core-fuzz -- -max_total_time=300
260260
-@cargo +nightly fuzz run mast_forest_validate --release --fuzz-dir miden-core-fuzz -- -max_total_time=300
261+
-@cargo +nightly fuzz run program_deserialize --release --fuzz-dir miden-core-fuzz -- -max_total_time=300
262+
-@cargo +nightly fuzz run kernel_deserialize --release --fuzz-dir miden-core-fuzz -- -max_total_time=300
263+
-@cargo +nightly fuzz run stack_io_deserialize --release --fuzz-dir miden-core-fuzz -- -max_total_time=300
264+
-@cargo +nightly fuzz run advice_inputs_deserialize --release --fuzz-dir miden-core-fuzz -- -max_total_time=300
265+
-@cargo +nightly fuzz run operation_deserialize --release --fuzz-dir miden-core-fuzz -- -max_total_time=300
266+
-@cargo +nightly fuzz run execution_proof_deserialize --release --fuzz-dir miden-core-fuzz -- -max_total_time=300
267+
-@cargo +nightly fuzz run precompile_request_deserialize --release --fuzz-dir miden-core-fuzz -- -max_total_time=300
268+
-@cargo +nightly fuzz run library_deserialize --release --fuzz-dir miden-core-fuzz -- -max_total_time=300
269+
-@cargo +nightly fuzz run package_deserialize --release --fuzz-dir miden-core-fuzz -- -max_total_time=300
261270

262271
.PHONY: fuzz-list
263272
fuzz-list: ## List available fuzz targets
@@ -271,3 +280,4 @@ fuzz-coverage: ## Generate coverage report for fuzz targets
271280
.PHONY: fuzz-seeds
272281
fuzz-seeds: ## Generate seed corpus files for fuzzing
273282
cargo test -p miden-core generate_fuzz_seeds -- --ignored --nocapture
283+
cargo test -p miden-mast-package generate_fuzz_seeds -- --ignored --nocapture

core/src/mast/merger/tests.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use super::*;
22
use crate::{
33
Felt, ONE, Word,
44
mast::{
5-
BasicBlockNodeBuilder, CallNodeBuilder, DecoratorId, ExternalNodeBuilder, LoopNodeBuilder,
5+
BasicBlockNodeBuilder, CallNodeBuilder, DecoratorId, DynNodeBuilder, ExternalNodeBuilder,
6+
LoopNodeBuilder,
67
node::{MastForestContributor, MastNodeExt},
78
},
89
operations::{DebugOptions, Decorator, Operation},
@@ -104,6 +105,37 @@ fn assert_child_id_lt_parent_id(forest: &MastForest) -> Result<(), &str> {
104105
Ok(())
105106
}
106107

108+
#[test]
109+
fn mast_forest_merge_preserves_dyn_callness_and_digest() {
110+
let mut forest = MastForest::new();
111+
112+
let dynexec_id = DynNodeBuilder::new_dyn().add_to_forest(&mut forest).unwrap();
113+
let dyncall_id = DynNodeBuilder::new_dyncall().add_to_forest(&mut forest).unwrap();
114+
forest.make_root(dynexec_id);
115+
forest.make_root(dyncall_id);
116+
117+
let dynexec_digest = forest[dynexec_id].digest();
118+
let dyncall_digest = forest[dyncall_id].digest();
119+
120+
let (merged, root_maps) = MastForest::merge([&forest]).unwrap();
121+
122+
let merged_dynexec_id = root_maps.map_root(0, &dynexec_id).unwrap();
123+
let merged_dyncall_id = root_maps.map_root(0, &dyncall_id).unwrap();
124+
125+
assert_ne!(
126+
merged_dynexec_id, merged_dyncall_id,
127+
"dynexec and dyncall nodes should not be deduplicated"
128+
);
129+
130+
let merged_dynexec = merged[merged_dynexec_id].unwrap_dyn();
131+
let merged_dyncall = merged[merged_dyncall_id].unwrap_dyn();
132+
133+
assert!(!merged_dynexec.is_dyncall(), "dynexec node should remain dynexec after merge");
134+
assert!(merged_dyncall.is_dyncall(), "dyncall node should remain dyncall after merge");
135+
assert_eq!(merged_dynexec.digest(), dynexec_digest, "dynexec digest should be preserved");
136+
assert_eq!(merged_dyncall.digest(), dyncall_digest, "dyncall digest should be preserved");
137+
}
138+
107139
/// Tests that Call(bar) still correctly calls the remapped bar block.
108140
///
109141
/// [Block(foo), Call(foo)]

core/src/mast/node/basic_block_node/mod.rs

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -545,20 +545,6 @@ impl BasicBlockNode {
545545
let indptr = batch.indptr();
546546
let ops = batch.ops();
547547

548-
// indptr should be monotonic non-decreasing in valid prefix
549-
for i in 0..batch.num_groups() {
550-
if indptr[i] > indptr[i + 1] {
551-
return Err(format!(
552-
"Batch {}: indptr[{}] {} > indptr[{}] {} - array is not monotonic",
553-
batch_idx,
554-
i,
555-
indptr[i],
556-
i + 1,
557-
indptr[i + 1]
558-
));
559-
}
560-
}
561-
562548
// Full array must be monotonic for serialization (delta encoding)
563549
for i in 0..indptr.len() - 1 {
564550
if indptr[i] > indptr[i + 1] {
@@ -573,10 +559,7 @@ impl BasicBlockNode {
573559
}
574560
}
575561

576-
// All indptr values should be within ops bounds
577562
let ops_len = ops.len();
578-
579-
// Final indptr value must equal ops.len()
580563
if indptr[indptr.len() - 1] != ops_len {
581564
return Err(format!(
582565
"Batch {}: final indptr value {} doesn't match ops.len() {}",
@@ -585,14 +568,6 @@ impl BasicBlockNode {
585568
ops_len
586569
));
587570
}
588-
for (i, &indptr_val) in indptr.iter().enumerate().take(batch.num_groups() + 1) {
589-
if indptr_val > ops_len {
590-
return Err(format!(
591-
"Batch {}: indptr[{}] {} exceeds ops length {}",
592-
batch_idx, i, indptr_val, ops_len
593-
));
594-
}
595-
}
596571

597572
// Check that each group has at most GROUP_SIZE operations
598573
for group_idx in 0..batch.num_groups() {

core/src/mast/node/call_node.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@ use miden_formatting::{
99
use serde::{Deserialize, Serialize};
1010

1111
use super::{MastForestContributor, MastNodeExt};
12+
#[cfg(debug_assertions)]
13+
use crate::mast::MastNode;
1214
use crate::{
1315
Felt, Word,
1416
chiplets::hasher,
1517
mast::{
16-
DecoratorId, DecoratorStore, MastForest, MastForestError, MastNode, MastNodeFingerprint,
17-
MastNodeId,
18+
DecoratorId, DecoratorStore, MastForest, MastForestError, MastNodeFingerprint, MastNodeId,
1819
},
1920
operations::opcodes,
2021
utils::{Idx, LookupByIdx},

core/src/mast/node/dyn_node.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ use core::fmt;
55
use serde::{Deserialize, Serialize};
66

77
use super::{MastForestContributor, MastNodeExt};
8+
#[cfg(debug_assertions)]
9+
use crate::mast::MastNode;
810
use crate::{
911
Felt, Word,
1012
mast::{
11-
DecoratorId, DecoratorStore, MastForest, MastForestError, MastNode, MastNodeFingerprint,
12-
MastNodeId,
13+
DecoratorId, DecoratorStore, MastForest, MastForestError, MastNodeFingerprint, MastNodeId,
1314
},
1415
operations::opcodes,
1516
prettier::{Document, PrettyPrint, const_text, nl},

core/src/mast/node/join_node.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ use core::fmt;
55
use serde::{Deserialize, Serialize};
66

77
use super::{MastForestContributor, MastNodeExt};
8+
#[cfg(debug_assertions)]
9+
use crate::mast::MastNode;
810
use crate::{
911
Felt, Word,
1012
chiplets::hasher,
1113
mast::{
12-
DecoratorId, DecoratorStore, MastForest, MastForestError, MastNode, MastNodeFingerprint,
13-
MastNodeId,
14+
DecoratorId, DecoratorStore, MastForest, MastForestError, MastNodeFingerprint, MastNodeId,
1415
},
1516
operations::opcodes,
1617
prettier::PrettyPrint,

core/src/mast/node/loop_node.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ use core::fmt;
55
use serde::{Deserialize, Serialize};
66

77
use super::{MastForestContributor, MastNodeExt};
8+
#[cfg(debug_assertions)]
9+
use crate::mast::MastNode;
810
use crate::{
911
Felt, Word,
1012
chiplets::hasher,
1113
mast::{
12-
DecoratorId, DecoratorStore, MastForest, MastForestError, MastNode, MastNodeFingerprint,
13-
MastNodeId,
14+
DecoratorId, DecoratorStore, MastForest, MastForestError, MastNodeFingerprint, MastNodeId,
1415
},
1516
operations::opcodes,
1617
prettier::PrettyPrint,
@@ -315,9 +316,7 @@ impl MastForestContributor for LoopNodeBuilder {
315316
let future_node_id = MastNodeId::new_unchecked(forest.nodes.len() as u32);
316317

317318
// Store node-level decorators in the centralized NodeToDecoratorIds for efficient access
318-
forest
319-
.debug_info
320-
.register_node_decorators(future_node_id, &before_enter, &after_exit);
319+
forest.register_node_decorators(future_node_id, &before_enter, &after_exit);
321320

322321
// Create the node in the forest with Linked variant from the start
323322
// Move the data directly without intermediate cloning

core/src/mast/node/split_node.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ use core::fmt;
55
use serde::{Deserialize, Serialize};
66

77
use super::{MastForestContributor, MastNodeExt};
8+
#[cfg(debug_assertions)]
9+
use crate::mast::MastNode;
810
use crate::{
911
Felt, Word,
1012
chiplets::hasher,
1113
mast::{
12-
DecoratorId, DecoratorStore, MastForest, MastForestError, MastNode, MastNodeFingerprint,
13-
MastNodeId,
14+
DecoratorId, DecoratorStore, MastForest, MastForestError, MastNodeFingerprint, MastNodeId,
1415
},
1516
operations::opcodes,
1617
prettier::PrettyPrint,

0 commit comments

Comments
 (0)