Skip to content
Merged
Show file tree
Hide file tree
Changes from 72 commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
45af24a
chore: set up constraint change tracking
adr1anh Apr 2, 2026
5df9b1b
refactor: inline tagged_assert_zero variants, remove tagging indirection
adr1anh Apr 2, 2026
9bc0b91
refactor: inline trivial assert wrappers in stack and decoder modules
adr1anh Apr 2, 2026
bb5cb22
refactor: remove empty section headers and apply lint fixes
adr1anh Apr 2, 2026
cf9722c
refactor: remove constraint tagging infrastructure
adr1anh Apr 2, 2026
a7dbe96
refactor: introduce MidenAirBuilder trait alias
adr1anh Apr 2, 2026
06c39d9
refactor: remove unused decoder constants and inline last assert wrapper
adr1anh Apr 2, 2026
fa1cce2
refactor: remove dead code and unnecessary allow(dead_code) annotations
adr1anh Apr 2, 2026
b7c32f8
refactor: remove unnecessary clone() calls on Copy types
adr1anh Apr 2, 2026
f06e0dd
refactor: use semantic assertion methods in constraint code
adr1anh Apr 2, 2026
6a886e9
refactor: inline field constants and centralize in constants.rs
adr1anh Apr 2, 2026
e4478fe
refactor: introduce BoolNot trait for boolean negation in constraints
adr1anh Apr 2, 2026
5880e08
refactor: defer Var-to-Expr conversions and simplify array construction
adr1anh Apr 2, 2026
313a9af
refactor: add ChipletFlags/ChipletSelectors structs with precomputed …
adr1anh Apr 2, 2026
000bd6a
refactor: thread ChipletSelectors through all constraint and bus func…
adr1anh Apr 2, 2026
7b487df
refactor: enforce all chiplet selectors are 1 in last row
adr1anh Apr 2, 2026
daf0f26
refactor: remove when_transition from chiplet constraints
adr1anh Apr 2, 2026
8d43331
refactor: add per-bus domain separation to Challenges encoding
adr1anh Apr 2, 2026
92ca9ca
refactor: narrow per-chiplet constraint functions to &ChipletFlags
adr1anh Apr 2, 2026
a572620
refactor: inline small constraint helper functions
adr1anh Apr 2, 2026
bc860be
refactor: add typed column structs, col map, and Borrow impls
adr1anh Apr 2, 2026
114cf15
refactor: wire MainCols into eval() — MainTraceRow becomes type alias
adr1anh Apr 2, 2026
8bdff1f
refactor: migrate range constraints to named struct fields
adr1anh Apr 2, 2026
ea6b215
refactor: migrate decoder constraints to DecoderCols named fields
adr1anh Apr 2, 2026
517dc4f
refactor: migrate stack constraints to StackCols named fields
adr1anh Apr 2, 2026
a4c7bbf
refactor: migrate bitwise chiplet constraints to BitwiseCols
adr1anh Apr 2, 2026
5c1b037
refactor: migrate hasher + memory chiplet constraints to typed cols
adr1anh Apr 2, 2026
5200b41
refactor: migrate ACE chiplet constraints to AceCols
adr1anh Apr 2, 2026
674e07d
refactor: migrate kernel ROM constraints to KernelRomCols
adr1anh Apr 2, 2026
d09b5dc
refactor: migrate chiplet bus wiring + hash_kernel to typed cols
adr1anh Apr 2, 2026
378d04f
refactor: migrate chiplets bus constraints to typed column structs
adr1anh Apr 2, 2026
8d8566e
refactor: post-review cleanup of typed column structs
adr1anh Apr 2, 2026
69d1a02
refactor: add typed chiplet accessors to MainCols, eliminate raw chip…
adr1anh Apr 2, 2026
e926705
chore: format imports in chiplet constraint files
adr1anh Apr 2, 2026
4146ab0
refactor: split chiplets bus into requests/responses modules, reduce …
adr1anh Apr 2, 2026
5aaf74a
refactor: apply constraint style rules — when() decomposition, semant…
adr1anh Apr 2, 2026
f0db2d5
refactor: flatten single-file stack constraint modules into sibling f…
adr1anh Apr 2, 2026
56ec41c
refactor: type ACE shared columns into named fields with QuadFeltExpr
adr1anh Apr 2, 2026
a4a1903
refactor: type periodic columns into named structs and simplify chipl…
adr1anh Apr 2, 2026
6c3d544
refactor: simplify op_flags with bit-selector pattern and iterative e…
adr1anh Apr 2, 2026
607d241
refactor: use Algebra trait bound and remove op_flags indirection
adr1anh Apr 2, 2026
2f7fd7d
fix: use core::array for no-std compatibility
adr1anh Apr 2, 2026
2f5dc9f
refactor(decoder): improve readability of composite flags
adr1anh Apr 2, 2026
4296f05
refactor(decoder): inline all constraint helpers into enforce_main an…
adr1anh Apr 2, 2026
860d340
refactor: decouple column layout types from trace storage
adr1anh Apr 2, 2026
967c0fb
Merge origin/next into constraint-simplification
adr1anh Apr 2, 2026
cbcb370
refactor(crypto): improve readability of crypto operation constraints
adr1anh Apr 2, 2026
dc0bec8
feat: add per-bus domain separation to ACE circuit and MASM verifier
adr1anh Apr 4, 2026
8d259ed
feat: add dead-node elimination pass to ACE DAG
adr1anh Apr 4, 2026
3379699
refactor: move column structs from trace/ to constraints/
adr1anh Apr 4, 2026
468acac
refactor: remove unsafe Index impls, rename MainTraceRow to MainCols
adr1anh Apr 4, 2026
90ce10e
refactor: merge chiplets bus sub-files back into single chiplets.rs
adr1anh Apr 5, 2026
e875d3d
Merge origin/next into constraint-simplification
adr1anh Apr 8, 2026
5389a12
refactor: unify periodic column generation with typed struct construc…
adr1anh Apr 8, 2026
4eb4a39
refactor: split hasher chiplet into controller and permutation sub-mo…
adr1anh Apr 13, 2026
db23d39
refactor: restructure hasher controller constraints by operation life…
adr1anh Apr 13, 2026
a037c8f
docs: clarify structural confinement bullet in hasher.md
adr1anh Apr 13, 2026
3f6dc13
refactor(hasher): tighten digest-routing gate to local soundness
adr1anh Apr 14, 2026
2196f49
Merge remote-tracking branch 'origin/next' into adr1anh/constraint-si…
adr1anh Apr 14, 2026
b8731df
docs: add changelog entry for PR #2856
adr1anh Apr 14, 2026
9a140df
docs(CONSTRAINT_CHANGES): record merge baseline and entries 44-46
adr1anh Apr 14, 2026
0cd3fa6
docs(CONSTRAINT_CHANGES): dedup boilerplate interpretations via ancho…
adr1anh Apr 14, 2026
ac21cfa
chore: drop constraint-refactor scratch files
adr1anh Apr 14, 2026
4164cd2
feat(core): add testable constraints regeneration command
huitseeker Apr 14, 2026
05ffd82
Fix core-lib constraints tool feature gating
huitseeker Apr 14, 2026
8c31a7a
ci: check recursive constraints for drift
huitseeker Apr 14, 2026
3eb18ab
Merge pull request #3002 from huitseeker/constraint-simplification
adr1anh Apr 14, 2026
c02ca89
refactor(bus): domain-separate hasher perm-link bus
adr1anh Apr 14, 2026
311f294
refactor(chiplets): fill s_ctrl selector via .fill(ONE) memset
adr1anh Apr 14, 2026
16246ba
revert(ace-codegen): drop stale dead-node elimination tests
adr1anh Apr 14, 2026
d2326eb
refactor(air): address PR review nits and add HALT boundary constraint
adr1anh Apr 16, 2026
d87517e
docs(air): enrich ACE chiplet column documentation
adr1anh Apr 16, 2026
423fb8d
refactor(air): address remaining PR review comments
adr1anh Apr 16, 2026
42a0521
Merge remote-tracking branch 'origin/next' into adr1anh/constraint-si…
adr1anh Apr 16, 2026
9289e66
fix(air): port stack_arith u32 constraint tests from origin/next
adr1anh Apr 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,21 @@ jobs:
echo "No documentation changes in crates/lib/core/docs/ - OK"
fi

check-constraints:
name: check recursive constraint artifacts
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Cleanup large tools for build space
uses: ./.github/actions/cleanup-runner
- uses: Swatinem/rust-cache@v2
with:
save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/next' }}
- name: Install rust
run: rustup update --no-self-update
- name: Check recursive constraint artifacts for drift
run: make check-constraints

run-examples:
name: run masm examples
runs-on: warp-ubuntu-latest-x64-4x
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,7 @@ crates/lib/core/assets/core.masl

# mdBook
book/

# Constraint analysis tooling
.constraint-tooling/
scripts/__pycache__/
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
- Documented non-overlap requirement for `memcopy_words`, `memcopy_elements`, and AEAD encrypt/decrypt procedures ([#2941](https://github.com/0xMiden/miden-vm/pull/2941)).
- Added chainable `Test` builders for common test setup in `miden-utils-testing` ([#2957](https://github.com/0xMiden/miden-vm/pull/2957)).
- Speed-up AUX range check trace generation by changing divisors to a flat Vec layout ([#2966](https://github.com/0xMiden/miden-vm/pull/2966)).
- Removed AIR constraint tagging instrumentation, applied a uniform constraint description style across components, and optimized constraint evaluation ([#2856](https://github.com/0xMiden/miden-vm/pull/2856)).

## 0.22.1
Comment thread
adr1anh marked this conversation as resolved.

#### Enhancements
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ help:
@printf " make test-prover # Test prover crate\n"
@printf " make test-core-lib # Test core-lib crate\n"
@printf " make test-verifier # Test verifier crate\n"
@printf " make check-constraints # Check core-lib constraint artifacts\n"
@printf " make regenerate-constraints # Regenerate core-lib constraint artifacts\n"
@printf "\nExamples:\n"
@printf " make test-air test=\"some_test\" # Test specific function\n"
@printf " make test-fast # Fast tests (no proptests/CLI)\n"
Expand Down Expand Up @@ -220,6 +222,14 @@ exec-avx2: ## Builds an executable with AVX2 acceleration enabled
exec-sve: ## Builds an executable with SVE acceleration enabled
RUSTFLAGS="-C target-feature=+sve" cargo build --profile optimized $(FEATURES_CONCURRENT_EXEC)

.PHONY: regenerate-constraints
regenerate-constraints: ## Regenerate core-lib constraint artifacts
cargo run --package miden-core-lib --features constraints-tools --bin regenerate-constraints -- --write

.PHONY: check-constraints
check-constraints: ## Check core-lib constraint artifacts for drift
cargo run --package miden-core-lib --features constraints-tools --bin regenerate-constraints -- --check

.PHONY: exec-info
exec-info: ## Builds an executable with log tree enabled
cargo build --profile optimized $(FEATURES_LOG_TREE)
Expand Down
1 change: 1 addition & 0 deletions air/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@ thiserror.workspace = true
tracing.workspace = true

[dev-dependencies]
insta.workspace = true
miden-ace-codegen = { workspace = true, features = ["testing"] }
proptest.workspace = true
40 changes: 30 additions & 10 deletions air/src/ace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@ pub enum MessageElement {
pub enum ProductFactor {
/// Claimed final value of an auxiliary trace column, by column index.
BusBoundary(usize),
/// A bus message computed from its elements as `alpha + sum(beta^i * elements[i])`.
Message(Vec<MessageElement>),
/// A bus message computed from its elements as `bus_prefix[bus] + sum(beta^i * elements[i])`.
/// The first field is the bus type index (see `trace::bus_types`).
Message(usize, Vec<MessageElement>),
/// Multiset product reduced from variable-length public inputs, by group index.
Vlpi(usize),
}
Expand Down Expand Up @@ -131,7 +132,7 @@ where
for factor in factors {
let node = match factor {
ProductFactor::BusBoundary(idx) => builder.input(InputKey::AuxBusBoundary(*idx)),
ProductFactor::Message(elements) => encode_bus_message(builder, elements),
ProductFactor::Message(bus, elements) => encode_bus_message(builder, *bus, elements),
ProductFactor::Vlpi(idx) => builder.input(InputKey::VlpiReduction(*idx)),
};
acc = builder.mul(acc, node);
Expand All @@ -154,20 +155,38 @@ where
sum
}

/// Encode a bus message as `alpha + sum(beta^i * elements[i])`.
fn encode_bus_message<EF>(builder: &mut DagBuilder<EF>, elements: &[MessageElement]) -> NodeId
/// Encode a bus message as `bus_prefix[bus] + sum(beta^i * elements[i])`.
///
/// The bus prefix provides domain separation: `bus_prefix[bus] = alpha + (bus+1) * gamma`
/// where `gamma = beta^MAX_MESSAGE_WIDTH`. This matches [`trace::Challenges::encode`].
fn encode_bus_message<EF>(
builder: &mut DagBuilder<EF>,
bus: usize,
elements: &[MessageElement],
) -> NodeId
where
EF: ExtensionField<Felt>,
{
let alpha = builder.input(InputKey::AuxRandAlpha);
let beta = builder.input(InputKey::AuxRandBeta);

// acc = alpha + sum(beta^i * elem_i)
// Compute gamma = beta^MAX_MESSAGE_WIDTH.
let mut gamma = builder.constant(EF::ONE);
for _ in 0..trace::MAX_MESSAGE_WIDTH {
gamma = builder.mul(gamma, beta);
}

// bus_prefix = alpha + (bus + 1) * gamma
let scale = builder.constant(EF::from(Felt::from_u32((bus as u32) + 1)));
let offset = builder.mul(gamma, scale);
let bus_prefix = builder.add(alpha, offset);

// acc = bus_prefix + sum(beta^i * elem_i)
//
// Beta powers are built incrementally. The DagBuilder is hash-consed, so
// identical beta^i nodes across multiple message encodings are shared
// automatically.
let mut acc = alpha;
let mut acc = bus_prefix;
let mut beta_power = builder.constant(EF::ONE);
for elem in elements {
let node = match elem {
Expand All @@ -190,6 +209,7 @@ where
pub fn reduced_aux_batch_config() -> ReducedAuxBatchConfig {
use MessageElement::{Constant, PublicInput};
use ProductFactor::{BusBoundary, Message, Vlpi};
use trace::bus_types;

// Aux boundary column indices.
let p1 = trace::DECODER_AUX_TRACE_OFFSET;
Expand Down Expand Up @@ -251,10 +271,10 @@ pub fn reduced_aux_batch_config() -> ReducedAuxBatchConfig {
BusBoundary(s_aux),
BusBoundary(b_hash_kernel),
BusBoundary(b_chiplets),
Message(ph_msg),
Message(default_msg),
Message(bus_types::BLOCK_HASH_TABLE, ph_msg),
Message(bus_types::LOG_PRECOMPILE_TRANSCRIPT, default_msg),
],
denominator: vec![Message(final_msg), Vlpi(0)],
denominator: vec![Message(bus_types::LOG_PRECOMPILE_TRANSCRIPT, final_msg), Vlpi(0)],
sum_columns: vec![b_range, v_wiring],
}
}
Expand Down
64 changes: 60 additions & 4 deletions air/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,10 @@ pub fn pcs_params() -> PcsParams {
/// Compile-time constant binding the Fiat-Shamir transcript to the Miden VM AIR.
/// Must match the constants in `crates/lib/core/asm/sys/vm/mod.masm`.
pub const RELATION_DIGEST: [Felt; 4] = [
Felt::new(14932224741264950205),
Felt::new(13231194489255299102),
Felt::new(9539190039789656767),
Felt::new(16072183680659208914),
Felt::new(789474107508207355),
Felt::new(6700560344624007800),
Felt::new(10413623302183279352),
Felt::new(1269032160905630127),
];

/// Observes PCS protocol parameters and per-proof trace height into the challenger.
Expand Down Expand Up @@ -293,3 +293,59 @@ pub fn keccak_config(params: PcsParams) -> MidenStarkConfig<KeccakLmcs, KeccakCh
challenger.observe_slice(&RELATION_DIGEST);
GenericStarkConfig::new(params, lmcs, Radix2DitParallel::default(), challenger)
}

#[cfg(test)]
mod tests {
extern crate alloc;
use alloc::vec::Vec;

use miden_ace_codegen::{AceConfig, LayoutKind};
use miden_core::{Felt, crypto::hash::Poseidon2, field::QuadFelt};

use crate::{ProcessorAir, ace};

const PROTOCOL_ID: u64 = 0;
const REGEN_HINT: &str = "cargo run -p miden-core-lib --features constraints-tools --bin regenerate-constraints -- --write";

/// Snapshot test: catches any AIR change that alters the constraint circuit.
///
/// If this test fails, regenerate with:
/// cargo run -p miden-core-lib --features constraints-tools --bin regenerate-constraints --
/// --write
#[test]
fn relation_digest_matches_current_air() {
let config = AceConfig {
num_quotient_chunks: 8,
num_vlpi_groups: 1,
layout: LayoutKind::Masm,
};
let air = ProcessorAir;
let batch_config = ace::reduced_aux_batch_config();
let circuit =
ace::build_batched_ace_circuit::<_, QuadFelt>(&air, config, &batch_config).unwrap();
let encoded = circuit.to_ace().unwrap();
let circuit_commitment: [Felt; 4] = encoded.circuit_hash().into();

let input: Vec<Felt> = core::iter::once(Felt::new(PROTOCOL_ID))
.chain(circuit_commitment.iter().copied())
.collect();
let digest = Poseidon2::hash_elements(&input);
let expected: Vec<u64> =
digest.as_elements().iter().map(|f| f.as_canonical_u64()).collect();

let snapshot = format!(
"num_inputs: {}\nnum_eval_gates: {}\nrelation_digest: {:?}",
encoded.num_vars(),
encoded.num_eval_rows(),
expected,
);
insta::assert_snapshot!(snapshot);

let actual: Vec<u64> =
super::RELATION_DIGEST.iter().map(|f| f.as_canonical_u64()).collect();
assert_eq!(
actual, expected,
"RELATION_DIGEST in config.rs is stale. Regenerate with: {REGEN_HINT}"
);
}
}
1 change: 0 additions & 1 deletion air/src/constraints/bus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
//! - v_wiring (ACE wiring LogUp)

/// Auxiliary trace column indices.
#[allow(dead_code)]
pub mod indices {
/// Block stack table (decoder control flow)
pub const P1_BLOCK_STACK: usize = 0;
Expand Down
Loading
Loading