Conversation
* mmr: reject oversized forests to prevent num_nodes panics Forest deserialization previously accepted unbounded usize values. For values > usize::MAX/2 + 1, Forest::num_nodes asserted and would panic when downstream APIs (peaks/open/delta) were called. An attacker could craft a serialized MMR with forest = usize::MAX/2 + 2 to crash consumers after deserialization. This change enforces a maximum forest size at construction and deserialization, removes infallible constructors in favor of fallible ones, makes leaf appends return errors, and adds tests to cover oversize and iterator growth paths so oversized inputs are rejected before any panic can occur. * mmr: cap forest size safely * mmr: simplify append flow and document forest invariant * mmr: trust apply invariants for new_peaks * mmr: hard-cap max leaves to 2^k-1 and simplify xor/or * mmr: remove redundant bounds checks and harden invariants * mmr: centralize mask->node count helper usage
This changes `LargeSmtForest::entries` to return an iterator over items that are `Result<TreeEntry>` instead of bare `TreeEntry`, ensuring that the potential failure of iteration in the backend is communicated clearly to the caller performing the iteration. We also add benchmarks to the iteration in order to confirm that the changes incur no performance impact.
This change makes it so all SMT operations that operate on batches of key-value pairs will reject any input where the same key occurs more than once. This ensures that all of the various SMT implementations are coherent on the results they provide as there are no longer order-dependent computations. This commit introduces no measurable performance change for any impacted code path. No performance regressions are included.
This commit makes it possible for all writes in the persistent backend of the LargeSmtForest to be flushed to disk in a manner that the user decides. The default remains `false`, providing higher write performance but less durability, and the user can set it to `true` for higher durability but lower write performance.
This commit adds the `add_lineages` batch endpoint to the forest, providing a far more efficient way to add many new lineages at once than simply calling `add_lineage` in a loop. It originally experimented with additional `open_many` and `get_many` endpoints, but these proved no more efficient than simply calling `open` and `get` in a loop and have hence been removed. They are mentioned here for posterity. The new `add_lineages` endpoint is accompanied by comprehensive tests, as well as benchmarks to establish baseline performance. It is faster than calling `add_lineage` in a loop as soon as more than five lineages are being added when used in conjunction with the persistent backend, and when it is slower it is not by a significant amount. It is highly recommended to use this endpoint when adding multiple lineages at once. The exact performance profile is backend-dependent. This commit also includes some additional benchmarks for the large forest that were necessary to validate that performance had not changed for existing endpoints while making changes.
* Add curated Clippy guardrails Port the curated xclippy/xclippy-fix workflow from miden-vm to this workspace.\n\nEnable only the optional Clippy lints that currently pass without code fixes, wire the Make targets and existing lint CI to use that curated set. * Preserve xclippy alias order Exclude .cargo/config.toml from Taplo formatting and restore the Cargo alias argv order so the clippy CI job invokes the xclippy aliases correctly.
The type was previously used to perform lexicographic comparisons between words, but that behavior is now encapsulated in the default `Ord` instance for word, so the type is unnecessary.
This helps avoid the need for ser/de helpers due to the orphan rule, and is a simple change that relies on the existing `&str` ser/de machinery. It also now implements `Serializable` for `String` in terms of `str` for consistency.
This commit removes the `WORD_SIZE_FELTS` and `WORD_SIZE_BYTES` module-level constants in favor of the associated constants `Word::NUM_ELEMENTS` and `Word::SERIALIZED_SIZE` respectively. This makes the API more consistent while incurring no functional or performance regressions. It also removes `WORD_SIZE` from `miden-crypto` to help harmonize usage as the constant's name was potentially misleading. If we are making a breaking API change anyway, we might as well harmonize usages wholesale.
chore(deps): drop `patch` versioning for remaining plonky3 deps
This commit eagerly computes historical entry counts when creating the history deltas, making it possible to provide the true historical entry counts without traversing the historical entries of the tree. This drastically improves the performance of `entry_count`, while avoiding any regressions in other code paths.
feat: update Poseidon2 to match upstream P3
* Bump toolchain and refresh rand lockfiles * ci: remove toolchain override for cargo msrv
* perf: make some operations for Goldilocks faster * chore: update CHANGELOG.md * apply review * chore: address review nits after rebasing --------- Co-authored-by: François Garillot <francois@garillot.net>
#961) * ci: trim nextest matrix and cache rust builds The nextest jobs spend most of their time compiling, not running tests. Local runs were 94.28s cold / 2.43s warm for default, 28.84s / 1.25s for no-std, and 137.33s / 0.77s for large-smt. Restoring rust-cache lets CI reuse those artifacts instead of rebuilding them from scratch. The nightly nextest rows did not cover extra behavior. Recent CI runs on April 13, 2026 took almost the same time on stable and nightly, and the test targets do not rely on unstable Rust features. Keeping the stable lane preserves coverage while cutting duplicate work. The large-smt filter was also stale. It matched merkle::smt::full::large, but the real tests live under merkle::smt::large. This change moves those tests into the large-smt lane, keeps the split disjoint, and updates the Makefile text to match what the target runs. * ci: move heavy nextest jobs to WarpBuild The longest test jobs are compile-bound, so they get the biggest payoff from a faster runner and the matching WarpBuild Rust cache. Local runs were 94.28s cold / 2.43s warm for default, 28.84s / 1.25s for no-std, and 137.33s / 0.77s for large-smt. This keeps the change small. Only the main test matrix and the concurrent SMT nextest job move to warp-ubuntu-latest-x64-4x with WarpBuilds/rust-cache@v2. The rest of CI stays as it is.
* chore(clippy): add curated lint set and fix violations * fix: opt in to unused-qualifications
Decouple log trace heights from AirInstance, carrying them instead in StarkProof where they are observed into the Fiat-Shamir challenger before the transcript begins. This makes the protocol identity depend on the heights without requiring the verifier to know them a priori. AirInstance now holds only public_values and var_len_public_inputs. The instance module moves from miden-lifted-air to miden-lifted-stark, since it now depends on protocol-level concerns (StarkProof). Validation is refactored into validate_inputs() which takes instances and log_trace_heights as separate arguments. AirWitness::to_instance() is simplified (no longer fallible). verify_single no longer takes log_trace_height as a parameter - it is read from the proof. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The AirInstance / validate_instances symbols no longer exist in miden-lifted-air; their doc references needed to be rewritten. Also drop a redundant explicit link target in instance.rs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Address review feedback on #956: - Replace the instance/height count `assert_eq!` with a `HeightCountMismatch` error variant so malformed proofs surface as `VerifierError::Instance` instead of panicking the verifier process. - Bound each `log_h ≤ MAX_LOG_DOMAIN_SIZE` before `1usize << log_h` and `two_adic_generator(log_h)`, returning `LogHeightTooLarge`. - Introduce `InstanceShapes` to own the per-instance shape metadata previously stored as a loose `Vec<u8>` on `StarkProof`, with a shared `observe()` helper used by the prover, verifier, and `StarkTranscript::from_proof` so the Fiat-Shamir encoding is centralized. - Include `instance_shapes.size_in_bytes()` in `StarkProof::size_in_bytes` so the lifted bench doesn't undercount proof size. - Split `AirValidationError` into structural errors (`AirStructureError`, intrinsic to an AIR, lives in `miden-lifted-air`) and `InstanceValidationError` (instance/protocol-level, lives in `miden-lifted-stark::instance`). - Derive `Debug` on `AirInstance`, `AirWitness`, and `InstanceShapes`; add a manual `Debug` impl for `StarkProof` under a `Commitment: Debug` bound. - Update verifier module docs to reflect that `InstanceShapes` is the one statement component observed internally (callers must not pre-observe). Adds tests covering the new malformed-proof paths: count mismatch, oversized log heights, and non-power-of-two trace heights in the prover. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nd add Debug for StarkOutput Address further review on #956: - Restore `Serialize` / `Deserialize` on `StarkProof` and `InstanceShapes` (lost when `StarkProof` stopped being a type alias for `TranscriptData`). `StarkProof` routes the serde bounds through `TranscriptData<F, Commitment>` so the derive does not require `SC: Serialize`. - Add a manual `Debug` impl for `StarkOutput` mirroring the `StarkProof` pattern (bounded on `StarkDigest` and `Commitment` rather than `SC`). - Tighten the CHANGELOG entry to describe the migration without the incorrect miden-vm#2550 reference. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… bound Make StarkProof fields pub(crate) and expose wire-format summaries via accessors (num_traces, num_field_elements, num_commitments). Read per-instance log trace heights by parsing with StarkTranscript::from_proof, which now carries the shape metadata on the returned transcript. Replace the MAX_LOG_DOMAIN_SIZE guard with log_h + log_blowup <= TWO_ADICITY so the check matches the actual downstream two_adic_generator call on the LDE domain. Validate before observing into the challenger, so a rejected shape never contaminates the Fiat-Shamir state. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ffer Sample and discard an extension-field challenge right after observing the instance shapes in both prover and verifier (and in StarkTranscript::from_proof), so that subsequent Fiat-Shamir challenges commit to all previously absorbed inputs regardless of sponge state. Exposed as `instance_challenge` on `StarkTranscript` for visibility. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ng TODOs Strip "currently" and TODO(#941) forward-looking references from user-facing docs, fix stale `validate_instances` / `miden_lifted_air::AirWitness` paths left over from the instance-module move, correct the `src/verifier/proof.rs` entry in the modules table, and reframe the verifier multi-trace ordering contract as "match the prover's order" rather than "protocol requires ascending" — ascending is a prover-side cyclic-extension constraint, not a verifier requirement. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Prior to this commit, `SecretKey` could be used both for signing and for Diffie-Hellman key exchange. Now these responsibilities are separated into `SigningKey` and `KeyExchangeKey` in order to prevent accidental misuse and be more clear about the security properties of the keys.
…dering requirement The prover and verifier no longer require instances to be passed in ascending trace-height order. Instead, InstanceShapes::from_trace_heights sorts internally by (log_height, caller_index) and records the permutation as air_order. The verifier reads air_order from the proof to reorder caller instances before processing. Key changes: - InstanceShapes gains an air_order field (not absorbed into Fiat-Shamir) - from_trace_heights returns Self (no separate permutation), with reorder() to apply the permutation to caller-ordered data - NotAscending error replaced by InvalidAirOrder for untrusted proof validation - observe renamed to observe_heights for clarity - AirWitness derives Clone + Copy (all fields are references) - Fiat-Shamir docs reworked: the caller must bind protocol parameters, public values, var-len inputs, and the AIR identity + ordering Closes #941 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add StarkProof::air_order() public accessor; keep instance_shapes opaque - reorder() validates air_order before applying (prevents panic on malformed proofs) - Restore ascending-height check as real error (HeightsNotAscending) in validate_inputs - Clarify Fiat-Shamir binding contract: list concrete items (protocol params, AIR configs, air_order, public inputs) without prescribing how/order - Add AirOrderLengthMismatch error variant for accurate diagnostics - Make debug.rs sort key explicit (height, i) to avoid reliance on sort stability - Demote InstanceShapes::len/is_empty/reorder to pub(crate) - Update doc examples to use proof.air_order() - Update verifier README protocol flow to include air_order validation step Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… open (#971) * optimize * add changelog
* docs(contributing): explain contribution quality expectations Add the same contribution-quality expectations used in miden-vm and make the signed-commit requirement explicit.\n\nOutcome: contributors can see, before they open a PR, that small drive-by edits may be declined, that each change should be tied to an assigned issue, and that signed commits are part of the normal contribution path.\n\nThis commit is documentation-only. It does not rely on GitHub Actions knowledge and gives reviewers a stable policy reference that later workflow automation can point at. * ci(contribution-quality): review PR metadata without running PR code Add the contribution-quality workflow from miden-vm to this repository.\n\nOutcome: when a PR is opened or updated, GitHub can check whether the description links an issue, explains the rationale, and gives reviewers a test plan. If the PR misses those basics, the workflow leaves a comment and can apply a label for follow-up.\n\nThe important GitHub Actions detail is safety: this job uses pull_request_target but never checks out the PR branch. It reads PR metadata through the GitHub API, which lets maintainers automate guidance without executing untrusted fork code. * ci(lint): run cargo-machete through the repo's lint tooling Replace the dedicated cargo-machete action with an explicit tool install and run the existing make target instead.\n\nOutcome: the lint workflow still checks Cargo manifests for unused dependencies, but now the GitHub Actions steps mirror the command contributors run locally: make machete. That gives newcomers one documented path to follow instead of two slightly different setups.\n\nFor people unused to Actions, the pattern is simple: checkout the repo, install the CLI tool, then run the same project command you would run on your machine. Keeping CI close to the Makefile reduces surprise when a lint job fails. * ci(signed-commits): reject unsigned PR commits Add the signed-commits workflow used in miden-vm.\n\nOutcome: pull requests now fail when they contain unsigned commits, and the workflow leaves a short comment that shows which commits need to be re-signed.\n\nFor readers new to GitHub Actions, this job stays on the safe side of pull_request_target: it reads commit verification data from the GitHub API and does not check out or run code from the PR branch.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is a tracking PR for v0.24.0 release.