feat(tbtc/signer): Rust FROST/ROAST signer (distributed DKG, interactive-only signing, FFI ABI 2.0)#4005
feat(tbtc/signer): Rust FROST/ROAST signer (distributed DKG, interactive-only signing, FFI ABI 2.0)#4005mswilkison wants to merge 244 commits into
Conversation
Lands the Rust signer at pkg/tbtc/signer/ alongside the existing Go DKG coordinator. Mirrors the signer slice of tlabs-xyz/tbtc:feat/frost-schnorr-migration (PR #10) at frozen tag frost-extraction-source-v1. Per extraction plan v38 §3.1, the signer co-locates with keep-core because: (a) HSM enforcement is external to signer code (standard PKCS#11/KMIP client), doesn't force a separate audit lifecycle; (b) coordinator coupling dominates (B-2 DKG coordinator already lives in this repo via PR #3866); (c) TEE adoption later is reversible without forcing a repo split. Layout - pkg/tbtc/signer/ — Rust crate with own Cargo.toml - pkg/tbtc/signer/docs/ — signer + ROAST + TEE specs - pkg/tbtc/signer/docs/formal/models/ — ROAST + TEE TLA+ models - pkg/tbtc/signer/scripts/formal/ — ROAST vector + TLA runner - pkg/tbtc/signer/test/vectors/ — roast-attempt-context-v1.json Files (49 total) - 47 mirror status (Rust source, signer docs, ROAST docs, TLA models, test vector, etc.) - 2 allowlisted-divergence: - pkg/tbtc/signer/scripts/formal/check_roast_attempt_context_vectors.mjs (path normalization to signer-repo paths) - pkg/tbtc/signer/scripts/formal/run_tla_models.sh (MODELS_PATH env var refactor; default pkg/tbtc/signer/docs/formal/models/) Provenance - Source repository: tlabs-xyz/tbtc - Source branch: feat/frost-schnorr-migration - Source tag (frozen): frost-extraction-source-v1 - Source commit (H): 52389bd5cccb5daeef195671feb7ca46be6e2f37 - Source manifest: extraction/frost-extraction-source-manifest.json (manifestSha256: f7295fb738104501eb6c0c2447a42122ceb5f684c7a7c5dfb50ecb0bde3a0ea0) - Source PR(s): #425 (tbtc-signer error codes) + the full FROST migration series; complete list per source manifest's commit range over tools/tbtc-signer/ and signer-adjacent docs/scripts. Build wiring (follow-up) This PR lands the signer source code, docs, vectors, and scripts. Rust toolchain CI integration (cargo build/test/clippy/fmt as a separate CI job alongside the existing Go jobs) is a follow-up — Go workspace ignores non-Go subdirectories automatically; the cargo crate at pkg/tbtc/signer/Cargo.toml is independently buildable. Known TBD (resolved pre-merge) - 2 allowlisted-divergence files have expectedTargetSha256 = <TBD> in the source manifest. Path normalization transformations need to be applied to make the scripts run in pkg/tbtc/signer/ context; this PR ships the source verbatim, follow-up commits on this branch apply the transformations before merge. - Dual signoff required on each allowlisted-divergence entry per plan v38 §4.2 (extraction lead + canonical repo maintainer). Verification (pre-merge per plan v38 §7.2) - 47 mirror files: sha256 equality between git show frost-extraction-source-v1:<sourcePath> and this PR's content at pkg/tbtc/signer/<targetPath>. - 2 allowlisted-divergence files: sha256 == expectedTargetSha256 (recorded post-transformation in source manifest). - PR-scoped rogue-file check: git diff --name-only main...HEAD only contains files in manifest's fileMap with targetKey "signer". Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis PR introduces ChangesCore Signer Implementation
Admission Checking & Policy Enforcement
Benchmarking & Formal Test Vectors
TLA+ Formal Verification Models
Design Documentation & Specifications
Build Configuration & Scripts
🎯 4 (Complex) | ⏱️ ~75 minutes
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…ripts
Per extraction plan v38 §4.4, allowlisted-divergence files require
content normalization for the canonical context. This commit applies
the transformations declared in the source manifest for the 2 signer-
side allowlisted-divergence entries.
Transformations
- pkg/tbtc/signer/scripts/formal/check_roast_attempt_context_vectors.mjs:
Rewrite vector path from
`docs/frost-migration/test-vectors/roast-attempt-context-v1.json`
to canonical signer layout
`test/vectors/roast-attempt-context-v1.json`
(both relative to rootDir which is two levels up from the script
location; in canonical context that's pkg/tbtc/signer/)
- pkg/tbtc/signer/scripts/formal/run_tla_models.sh:
Rewrite MODEL_DIR default from
`$ROOT_DIR/docs/frost-migration/formal-verification/models`
to canonical signer layout
`$ROOT_DIR/docs/formal/models`
Plus MODELS_PATH env-var override for alternate environments (CI
matrices, local dev trees). ROOT_DIR is unchanged
(`$(dirname $BASH_SOURCE)/../..` resolves to pkg/tbtc/signer/ here).
Verification
- Both files retain identical behavior to their monorepo counterparts
when invoked from canonical signer layout
- Comments added documenting the path normalization with reference back
to the source manifest's allowlisted-divergence status
Recompute expectedTargetSha256 for both entries in the source manifest
and collect dual signoff before merge per plan v38 §4.2.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 13
🧹 Nitpick comments (3)
pkg/tbtc/signer/src/api.rs (1)
196-202: 💤 Low valueMissing
#[serde(default, skip_serializing_if)]onscript_tree_hex.All other
Option<T>fields in this file use#[serde(default, skip_serializing_if = "Option::is_none")], butscript_tree_hexdoes not. This inconsistency means the field will serialize asnullwhen absent, rather than being omitted.Suggested fix
pub struct BuildTaprootTxRequest { pub session_id: String, pub inputs: Vec<TxInput>, pub outputs: Vec<TxOutput>, + #[serde(default, skip_serializing_if = "Option::is_none")] pub script_tree_hex: Option<String>, }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pkg/tbtc/signer/src/api.rs` around lines 196 - 202, The BuildTaprootTxRequest struct's script_tree_hex Option field lacks the serde attributes used elsewhere; update the declaration of BuildTaprootTxRequest so the script_tree_hex field is annotated with #[serde(default, skip_serializing_if = "Option::is_none")] to match other Option<T> fields (preserving Clone/Debug/Deserialize/Serialize behavior) so it is omitted from serialized output when None instead of serializing as null.pkg/tbtc/signer/src/lib.rs (1)
391-421: 💤 Low value
std::env::set_varandstd::env::remove_varare not thread-safe.These functions are unsound in multi-threaded contexts and deprecated since Rust 1.66. While the tests appear to serialize access via
lock_test_state(), this guard must be held across all env mutations and checks within a test to prevent races with parallel test threads.Current usage appears safe given the locking pattern, but this is fragile. Consider using a dedicated test configuration mechanism that doesn't rely on process-wide environment mutation.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pkg/tbtc/signer/src/lib.rs` around lines 391 - 421, EnvVarGuard's methods (EnvVarGuard::set, EnvVarGuard::unset) and its Drop rely on std::env::set_var/remove_var which are process-wide and not thread-safe; replace this pattern with a test-scoped, non-global solution such as using a crate that provides scoped environment variables (e.g., temp_env or similar) or refactor tests to accept an injected configuration object instead of mutating process env; update usages to acquire and hold the new scoped guard for the entire duration of tests that need env changes (or pass a Config struct into functions under test) and remove direct calls to std::env::set_var/remove_var and the EnvVarGuard Drop behavior to avoid races.pkg/tbtc/signer/src/bin/admission_checker.rs (1)
257-276: 💤 Low valueConsider cleaning up the temp file if rename fails.
If
fs::renamefails (e.g., cross-filesystem move or permissions issue), the temp file remains on disk. Adding a cleanup attempt in the error path would improve robustness.♻️ Proposed cleanup on error
fs::write(&tmp_path, serialized).map_err(|error| { format!( "failed to write override replay registry temp file [{}]: {error}", tmp_path.display() ) })?; - fs::rename(&tmp_path, path).map_err(|error| { - format!( - "failed to persist override replay registry [{}]: {error}", - path.display() - ) - }) + fs::rename(&tmp_path, path).map_err(|error| { + let _ = fs::remove_file(&tmp_path); // Best-effort cleanup + format!( + "failed to persist override replay registry [{}]: {error}", + path.display() + ) + }) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pkg/tbtc/signer/src/bin/admission_checker.rs` around lines 257 - 276, persist_override_replay_registry currently leaves the temporary file (tmp_path) if fs::rename fails; modify the rename error path to attempt cleanup of tmp_path before returning the error. Specifically, call fs::remove_file(&tmp_path) (ignoring or logging its result) inside the Err branch that handles the rename failure so the function still returns the original formatted error for fs::rename but also tries to remove the leftover tmp file; reference persist_override_replay_registry, path, tmp_path, and fs::rename when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@pkg/tbtc/signer/docs/formal/models/README.md`:
- Around line 32-51: Update the incorrect repository paths in the traceability
matrix of pkg/tbtc/signer/docs/formal/models/README.md so links point to the
actual implementation and docs in this repo: change references to
tools/tbtc-signer/src/engine.rs to pkg/tbtc/signer/src/engine.rs for the entries
mentioning RoastAttemptStateMachine.tla (validate_attempt_context, replay
guards) and StateKeyProviderPolicy.tla (decode_encrypted_state_envelope,
encode_encrypted_state_envelope); change
docs/frost-migration/tee-whitelisted-signer-enforcement-plan.md to
pkg/tbtc/signer/docs/tee-whitelisted-signer-enforcement-plan.md for
TeeEnforcementModes.tla; and change
docs/frost-migration/roast-phase-5-security-rollout-gates.md to
pkg/tbtc/signer/docs/roast-phase-5-security-rollout-gates.md for
RoastRolloutPolicy.tla so readers can locate the referenced code and policy
docs.
In `@pkg/tbtc/signer/docs/roast-implementation-plan.md`:
- Line 93: Update the broken doc links in
pkg/tbtc/signer/docs/roast-implementation-plan.md by replacing repo-external
paths like `docs/frost-migration/roast-phase-0-spec-freeze.md` and any
`tools/tbtc-signer/...` references with the correct repo-local paths under
pkg/tbtc/signer/docs (or use correct relative paths from this markdown file);
search the file for all occurrences of `docs/frost-migration/...` and
`tools/tbtc-signer/...` (including the instances similar to the shown
`docs/frost-migration/roast-phase-0-spec-freeze.md`) and normalize each link so
it points to the new location in this package, preserving anchor fragments and
updating any link text as needed.
In `@pkg/tbtc/signer/docs/roast-phase-5-rollout-runbook.md`:
- Around line 26-29: Update the incorrect crate path used in the runbook
commands: replace occurrences of "cd tools/tbtc-signer" with "cd
pkg/tbtc/signer" for the benchmark command (`cargo bench --features
bench-restart-hook --bench phase5_roast`) and the chaos suite script invocation
(`./scripts/run_phase5_chaos_suite.sh`) so the commands run from the correct
crate directory.
In `@pkg/tbtc/signer/docs/roast-phase-5-security-rollout-gates.md`:
- Around line 92-99: Update stale repository paths in
roast-phase-5-security-rollout-gates.md: replace any occurrences of the old
tooling path "tools/tbtc-signer" with the new location "pkg/tbtc/signer" (e.g.,
update the run command `cd tools/tbtc-signer && cargo bench --features
bench-restart-hook --bench phase5_roast` to `cd pkg/tbtc/signer ...`), and
update any links referencing
`docs/frost-migration/roast-phase-5-baseline-calibration.md` to the document’s
new location in the repo (search for the exact link text and swap to the correct
path). Ensure all instances at the reported locations (around the run command
and the listed links) are changed consistently so operators following the
runbook hit the correct files and commands.
In `@pkg/tbtc/signer/docs/rust-rewrite-bootstrap.md`:
- Around line 10-13: The documentation still references the old crate path
"tools/tbtc-signer" and the validation command using that path; update every
occurrence to "pkg/tbtc/signer" in rust-rewrite-bootstrap.md (including the
header lines that list the crate, the C ABI include path `include/frost_tbtc.h`,
and any validation/build commands) so links and commands point to the colocated
pkg/tbtc/signer location; search for "tools/tbtc-signer" and replace with
"pkg/tbtc/signer" and verify the validation command and any examples reference
the new path.
In `@pkg/tbtc/signer/docs/signer-api-contract-decision-brief.md`:
- Around line 43-47: Update the two referenced paths in
signer-api-contract-decision-brief.md so they point to the mirrored crate
locations: replace `docs/frost-migration/rust-rewrite-bootstrap.md` with
`pkg/tbtc/signer/docs/frost-migration/rust-rewrite-bootstrap.md` and replace
`tools/tbtc-signer/src/lib.rs` with `pkg/tbtc/signer/src/lib.rs` (look for the
occurrences shown around the paragraph mentioning the bootstrap Rust crate and
file: `tools/tbtc-signer/src/lib.rs` and update those strings accordingly).
In `@pkg/tbtc/signer/docs/tbtc-signer-secret-material-hardening-plan.md`:
- Around line 6-7: The doc still uses the old crate path string
`tools/tbtc-signer`; update that scope reference to `pkg/tbtc/signer` throughout
the file (tbtc-signer-secret-material-hardening-plan.md) so the plan points to
the mirrored crate location, and scan for any other occurrences of
`tools/tbtc-signer` in this document to replace with `pkg/tbtc/signer`.
In `@pkg/tbtc/signer/docs/tee-whitelisted-signer-enforcement-plan.md`:
- Around line 296-298: Update the two broken cross-doc links in
pkg/tbtc/signer/docs/tee-whitelisted-signer-enforcement-plan.md (currently
referencing docs/frost-migration/roast-phase-5-security-rollout-gates.md and
docs/frost-migration/roast-phase-5-rollout-runbook.md on lines ~296–297) to
point to their correct locations inside this PR:
pkg/tbtc/signer/docs/roast-phase-5-security-rollout-gates.md and
pkg/tbtc/signer/docs/roast-phase-5-rollout-runbook.md so cross-document
navigation resolves correctly.
In `@pkg/tbtc/signer/README.md`:
- Around line 53-54: Update the README.md occurrence(s) that reference the old
path string "tools/tbtc-signer" to the new crate location "pkg/tbtc/signer":
search for and replace that path in all command snippets, code blocks, and file
references (e.g., cargo build/cd commands and any path bullets) so every
instance uses "pkg/tbtc/signer" consistently; ensure both shell commands and
prose file paths are updated, and run a quick grep for "tools/tbtc-signer" to
confirm no remaining references.
In `@pkg/tbtc/signer/scripts/admission-policy-v1.sample.json`:
- Line 8: Replace the non-hex placeholder value for the JSON key
dao_override_trust_root_pubkey_hex with a syntactically valid 32-byte hex string
(64 lowercase hex characters) so sample files and copy/paste validation don't
break; update the sample value to something like a 64-character hex placeholder
and leave replacement guidance in the README or nearby comment explaining it
must be replaced with the real x-only pubkey hex.
In `@pkg/tbtc/signer/scripts/formal/check_roast_attempt_context_vectors.mjs`:
- Around line 15-18: vectorsPath currently resolves to
"docs/frost-migration/test-vectors/roast-attempt-context-v1.json" and will fail
because the vectors live under "test/vectors"; update the path.join call that
constructs vectorsPath (using rootDir and the filename) to point to
"test/vectors/roast-attempt-context-v1.json" so the script loads the correct
file; ensure the change is made where vectorsPath is declared and used in this
module.
In `@pkg/tbtc/signer/scripts/formal/run_tla_models.sh`:
- Around line 4-5: The MODEL_DIR assignment in run_tla_models.sh is pointing to
the wrong path; update the MODEL_DIR variable (currently computed relative to
ROOT_DIR) to "$ROOT_DIR/docs/formal/models" so the directory existence check in
the script (around the directory existence test near line 20) succeeds; modify
the MODEL_DIR definition in the script (look for the MODEL_DIR variable
assignment and references) to use the corrected path and ensure any subsequent
uses of MODEL_DIR still reference this updated variable.
In `@pkg/tbtc/signer/tests/p2tr_signature_fraud_vectors.rs`:
- Around line 375-376: The test constructs vectors_path using the vectors_path
variable in pkg/tbtc/signer/tests/p2tr_signature_fraud_vectors.rs which
currently joins
"../../docs/frost-migration/test-vectors/p2tr-signature-fraud-v0.json" relative
to CARGO_MANIFEST_DIR and points to a non-existent file; fix by either adding
the missing p2tr-signature-fraud-v0.json to the repo at that path or update the
vectors_path join to the correct relative path where the JSON actually lives
(adjust the "../" segments or point to the canonical test-vectors location),
ensuring the variable name vectors_path and its usage remain unchanged.
---
Nitpick comments:
In `@pkg/tbtc/signer/src/api.rs`:
- Around line 196-202: The BuildTaprootTxRequest struct's script_tree_hex Option
field lacks the serde attributes used elsewhere; update the declaration of
BuildTaprootTxRequest so the script_tree_hex field is annotated with
#[serde(default, skip_serializing_if = "Option::is_none")] to match other
Option<T> fields (preserving Clone/Debug/Deserialize/Serialize behavior) so it
is omitted from serialized output when None instead of serializing as null.
In `@pkg/tbtc/signer/src/bin/admission_checker.rs`:
- Around line 257-276: persist_override_replay_registry currently leaves the
temporary file (tmp_path) if fs::rename fails; modify the rename error path to
attempt cleanup of tmp_path before returning the error. Specifically, call
fs::remove_file(&tmp_path) (ignoring or logging its result) inside the Err
branch that handles the rename failure so the function still returns the
original formatted error for fs::rename but also tries to remove the leftover
tmp file; reference persist_override_replay_registry, path, tmp_path, and
fs::rename when making the change.
In `@pkg/tbtc/signer/src/lib.rs`:
- Around line 391-421: EnvVarGuard's methods (EnvVarGuard::set,
EnvVarGuard::unset) and its Drop rely on std::env::set_var/remove_var which are
process-wide and not thread-safe; replace this pattern with a test-scoped,
non-global solution such as using a crate that provides scoped environment
variables (e.g., temp_env or similar) or refactor tests to accept an injected
configuration object instead of mutating process env; update usages to acquire
and hold the new scoped guard for the entire duration of tests that need env
changes (or pass a Config struct into functions under test) and remove direct
calls to std::env::set_var/remove_var and the EnvVarGuard Drop behavior to avoid
races.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: c0224eef-499a-42a2-a346-f06ef353278b
⛔ Files ignored due to path filters (1)
pkg/tbtc/signer/Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (48)
pkg/tbtc/signer/.gitignorepkg/tbtc/signer/Cargo.tomlpkg/tbtc/signer/README.mdpkg/tbtc/signer/benches/phase5_roast.rspkg/tbtc/signer/build.shpkg/tbtc/signer/docs/formal/models/README.mdpkg/tbtc/signer/docs/formal/models/RoastAttemptStateMachine.cfgpkg/tbtc/signer/docs/formal/models/RoastAttemptStateMachine.tlapkg/tbtc/signer/docs/formal/models/RoastRolloutPolicy.cfgpkg/tbtc/signer/docs/formal/models/RoastRolloutPolicy.tlapkg/tbtc/signer/docs/formal/models/StateKeyProviderPolicy.cfgpkg/tbtc/signer/docs/formal/models/StateKeyProviderPolicy.production.cfgpkg/tbtc/signer/docs/formal/models/StateKeyProviderPolicy.tlapkg/tbtc/signer/docs/formal/models/TeeEnforcementModes.cfgpkg/tbtc/signer/docs/formal/models/TeeEnforcementModes.tlapkg/tbtc/signer/docs/permissioned-signer-hardening-rfc.mdpkg/tbtc/signer/docs/roast-implementation-plan.mdpkg/tbtc/signer/docs/roast-phase-0-spec-freeze.mdpkg/tbtc/signer/docs/roast-phase-1.5-consumed-registry-integration.mdpkg/tbtc/signer/docs/roast-phase-2-coordinator-policy-enforcement.mdpkg/tbtc/signer/docs/roast-phase-3-attempt-transcript-replay-hardening.mdpkg/tbtc/signer/docs/roast-phase-4-liveness-policy-recovery.mdpkg/tbtc/signer/docs/roast-phase-5-baseline-calibration.mdpkg/tbtc/signer/docs/roast-phase-5-rollout-runbook.mdpkg/tbtc/signer/docs/roast-phase-5-security-rollout-gates.mdpkg/tbtc/signer/docs/rust-rewrite-bootstrap.mdpkg/tbtc/signer/docs/signer-api-contract-decision-brief.mdpkg/tbtc/signer/docs/tbtc-signer-secret-material-hardening-plan.mdpkg/tbtc/signer/docs/tee-whitelisted-signer-enforcement-plan.mdpkg/tbtc/signer/docs/true-late-t-of-n-finalize-considerations.mdpkg/tbtc/signer/include/frost_tbtc.hpkg/tbtc/signer/scripts/admission-candidate.sample.jsonpkg/tbtc/signer/scripts/admission-existing.sample.jsonpkg/tbtc/signer/scripts/admission-override-registry.sample.jsonpkg/tbtc/signer/scripts/admission-override.sample.jsonpkg/tbtc/signer/scripts/admission-policy-v1.sample.jsonpkg/tbtc/signer/scripts/formal/check_roast_attempt_context_vectors.mjspkg/tbtc/signer/scripts/formal/run_tla_models.shpkg/tbtc/signer/scripts/run_phase5_chaos_suite.shpkg/tbtc/signer/src/api.rspkg/tbtc/signer/src/bin/admission_checker.rspkg/tbtc/signer/src/engine.rspkg/tbtc/signer/src/errors.rspkg/tbtc/signer/src/ffi.rspkg/tbtc/signer/src/go_math_rand.rspkg/tbtc/signer/src/lib.rspkg/tbtc/signer/test/vectors/roast-attempt-context-v1.jsonpkg/tbtc/signer/tests/p2tr_signature_fraud_vectors.rs
Adds a focused workflow that runs the Rust signer's formal-invariant test suite + TLA model checks. Moved from threshold-network/tbtc-v2/.github/workflows/ci-formal-verification.yml (jobs `signer-formal-invariants` + `tla-model-checks`) per extraction plan v38 §3.1 — the signer code lives here at pkg/tbtc/signer/, not in tbtc-v2, so the CI jobs that exercise it belong here too. Jobs - signer-formal-invariants: cargo test --manifest-path pkg/tbtc/signer/ Cargo.toml formal_verification_ (filter to formal-only cases) - tla-model-checks: pkg/tbtc/signer/scripts/formal/run_tla_models.sh (iterates over .cfg files in pkg/tbtc/signer/docs/formal/models/ and runs TLC against each; MODELS_PATH env var allows override per the path-normalization commit b84b574c on this branch) Triggers - pull_request on pkg/tbtc/signer/** changes + this workflow file - schedule nightly at 05:23 UTC (mirrors monorepo's pattern of running formal invariants both on PRs and nightly) - workflow_dispatch for manual runs Related changes in companion PR threshold-network/tbtc-v2#971: - Removed these jobs from canonical tbtc-v2's ci-formal-verification.yml - Added a comment in that file pointing here Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/tbtc-signer-formal.yml:
- Around line 25-26: The checkout steps using actions/checkout@v4 persist git
credentials by default; update each Checkout step (the uses: actions/checkout@v4
entries) to add with: persist-credentials: false so credentials are not stored
in the runner after checkout. Ensure both occurrences of actions/checkout@v4 in
the workflow are modified accordingly.
- Line 26: Update the GitHub Actions workflow to pin action versions and harden
checkout credentials: replace occurrences of actions/checkout@v4 with
actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 and add with:
persist-credentials: false to both checkout steps that use checkout, replace
dtolnay/rust-toolchain@stable with
dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8, and replace
actions/setup-java@v4 with
actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 so the workflow pins
SHA-based commits and disables persisting credentials on checkout.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 88553e79-6db4-4e95-98fe-00c56e1bc640
📒 Files selected for processing (1)
.github/workflows/tbtc-signer-formal.yml
Resolves CI failures on PR #4005 (signer mirror): 1. TLA model checks: run_tla_models.sh lacked executable bit at canonical HEAD. CI ran the script directly (no `bash` prefix), which fails with `Permission denied`. Fixed via `git update-index --chmod=+x`. 2. Signer formal invariants: engine.rs's formal_verification_roast_attempt_context_shared_vectors_match_ expected_values test referenced vectors at a path stale from the umbrella's docs/frost-migration/test-vectors/ layout. The manifest places the vector at the canonical-signer test/vectors/ subdir (pkg/tbtc/signer/test/vectors/roast-attempt-context-v1.json per the source-to-target map). Updated the `PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(...)` argument from `../../docs/frost-migration/test-vectors/roast-attempt-context-v1.json` (umbrella-relative) to `test/vectors/roast-attempt-context-v1.json` (signer-CARGO_MANIFEST_DIR-relative, where the vector actually lives at canonical HEAD). Verified locally: - ls -l shows executable bit set on run_tla_models.sh - engine.rs path now resolves to the correct mirror location - Vector exists at pkg/tbtc/signer/test/vectors/roast-attempt-context-v1.json Same fix needs to be applied to PR #4007 (stacked on #4005) in a follow-up commit on its branch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PR #4005 signer formal invariants test formal_verification_p2tr_signature_fraud_vectors_match_bitcoin_crate was failing because: 1. The umbrella source manifest only mapped p2tr-signature-fraud-v0.json to the tbtc-v2 target (docs/test-vectors/). It was not mirrored to the keep-core (signer) target. 2. tests/p2tr_signature_fraud_vectors.rs referenced the vector at the umbrella-relative path `../../docs/frost-migration/test-vectors/p2tr-signature-fraud-v0.json` (CARGO_MANIFEST_DIR-relative -> repo-root + docs/frost-migration/...). That directory does not exist on canonical keep-core. This is a structural omission in the manifest, not a divergence: the cross-language vector test exists in both Solidity (tbtc-v2 side) and Rust (signer side), and the vector is genuinely needed in both places to verify cross-implementation consistency. Fix - Mirror p2tr-signature-fraud-v0.json (598 lines, byte-identical content from tbtc-v2 mirror at docs/test-vectors/) to pkg/tbtc/signer/test/vectors/p2tr-signature-fraud-v0.json. - Update the test path in tests/p2tr_signature_fraud_vectors.rs from `../../docs/frost-migration/test-vectors/p2tr-signature-fraud-v0.json` to `test/vectors/p2tr-signature-fraud-v0.json` (CARGO_MANIFEST_DIR = pkg/tbtc/signer/, so test/vectors/... resolves correctly). Two stale comment references remain in - pkg/tbtc/signer/docs/roast-implementation-plan.md:265 - pkg/tbtc/signer/scripts/formal/check_roast_attempt_context_vectors.mjs:19 Both are comment-only doc pointers to the source layout; they do not affect runtime. Left as-is to preserve the umbrella -> canonical provenance trail. Manifest update follows in a stacked PR on tlabs-xyz/tbtc#10: - Add p2tr-signature-fraud-v0.json -> signer target mapping (test/vectors/p2tr-signature-fraud-v0.json). - Reclassify tests/p2tr_signature_fraud_vectors.rs from mirror to allowlisted-divergence (path differs from umbrella). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Stacked on extraction/frost-signer-mirror-2026-05-26 / PR #4005. Adds optional taproot_merkle_root_hex to start/finalize signing rounds, binds it into request fingerprints and round IDs, signs and aggregates with frost-secp256k1-tr Taproot tweaks, and verifies tweaked aggregates in tests. Verification: cargo test in pkg/tbtc/signer.
## Stack Rust signer review-fix stack 1 of 2. - Base: `extraction/frost-signer-mirror-2026-05-26` ([#4005](#4005)) - Follow-up: [#4156](#4156) — admission-attestation validation ## What changed - Retain the `RefreshShares` symbol but fail closed with terminal code `cryptographic_refresh_not_supported` until a multi-round, zero-constant FROST refresh protocol exists. - Bump the FFI contract from ABI 3.3 to 4.0 so ABI-3 consumers reject the incompatible success-to-error response change during startup negotiation. - Remove the SHA-256 pseudo-refresh path, its process-local pending-operation machinery, and tests that encoded invalid refresh-success semantics. - Prove rejected refresh requests leave DKG key packages, the public package, lifecycle state, and persisted bytes unchanged. - Anchor the first refresh deadline and overdue metric to durable DKG creation time. - Treat metadata from the retired synthetic refresh stub as non-authoritative: it cannot postpone cadence, increment valid refresh counts, or claim key continuity. - Mark persisted synthetic refresh-only sessions without a DKG anchor immediately overdue in both status and telemetry, including when the system clock saturates at the Unix epoch. ## Review findings addressed - P1: implement cryptographic refresh instead of hashing shares — the unsafe one-shot operation now rejects and returns no replacement material. - P2: anchor the first refresh deadline to DKG creation — status and telemetry share the same durable deadline helper. - P2: bump the ABI for the incompatible refresh response — the endpoint now reports ABI 4.0 with its minor version reset to zero. - P1: mark unanchored legacy refresh sessions overdue — untrusted refresh artifacts now resolve to an explicit, unconditionally overdue sentinel instead of a sliding deadline. The C symbol, request shape, response envelope, and reserved response type remain present; the major version makes the changed status and JSON semantics explicit. ## Verification - `cargo fmt --manifest-path pkg/tbtc/signer/Cargo.toml -- --check` - `cargo check --locked --manifest-path pkg/tbtc/signer/Cargo.toml --all-targets` - `cargo clippy --locked --manifest-path pkg/tbtc/signer/Cargo.toml --all-targets -- -D warnings` - `cargo test --locked --manifest-path pkg/tbtc/signer/Cargo.toml` - `cargo test --locked --manifest-path pkg/tbtc/signer/Cargo.toml formal_verification_` - `pkg/tbtc/signer/scripts/run_phase5_chaos_suite.sh` - `git diff --check` The TLA+ runner was not available locally because this machine has no Java runtime; CI remains the authoritative model-check gate.
## Stack Rust signer review-fix stack 2 of 2. - Depends on: [#4155](#4155) - Ultimate base: `extraction/frost-signer-mirror-2026-05-26` ([#4005](#4005)) ## What changed - Reject an empty or whitespace-only policy `required_attestation_status` with `required_attestation_status_missing`. - Reject an empty or whitespace-only candidate `attestation_status` with `attestation_status_missing`. - Compare statuses only after both normalized values are non-empty, avoiding a misleading mismatch reason for missing data. - Preserve case-insensitive, whitespace-normalized matching for legitimate non-empty values. ## Review finding addressed - P2: reject empty attestation statuses before comparing them — an empty policy and empty candidate can no longer normalize to equality and pass admission. ## Verification - `cargo fmt --manifest-path pkg/tbtc/signer/Cargo.toml -- --check` - `cargo check --locked --manifest-path pkg/tbtc/signer/Cargo.toml --all-targets` - `cargo clippy --locked --manifest-path pkg/tbtc/signer/Cargo.toml --all-targets -- -D warnings` - `cargo test --locked --manifest-path pkg/tbtc/signer/Cargo.toml` - `cargo test --locked --manifest-path pkg/tbtc/signer/Cargo.toml --bin admission_checker attestation` - `git diff --check`
…ee-oracle-2026-07-13
## Stack Rust signer review-fix stack 3 of 3. - Depends on: #4158, which depends on #4157 - Ultimate base: `extraction/frost-signer-mirror-2026-05-26` (#4005) Merge #4157 and #4158 first, then retarget this PR down the stack. ## What changed - Serialize the complete first fallible state load and migration behind a dedicated process-local initialization mutex. - Double-check the OnceLock after acquiring the initializer mutex so concurrent first callers invoke the loader and any in-place migration only once. - Keep the initializer separate from `STATE_FILE_LOCK`, avoiding lock-order recursion when the loader resolves the active state path. - Recover the initializer token after mutex poisoning and leave the OnceLock unset after load errors so later calls can retry. - Add deterministic concurrency and failure-retry regressions against the same helper used by production `state()`. ## Review finding addressed - P2: serialize first-time state loading and migration. ## Verification - `cargo fmt --manifest-path pkg/tbtc/signer/Cargo.toml -- --check` - `cargo check --locked --manifest-path pkg/tbtc/signer/Cargo.toml --all-targets` - `cargo clippy --locked --manifest-path pkg/tbtc/signer/Cargo.toml --all-targets -- -D warnings` - `cargo test --locked --manifest-path pkg/tbtc/signer/Cargo.toml` (263 passed, 1 ignored; the ignored multiprocess helper passes in its child process; 28 binary and 1 integration test passed) - `cargo test --locked --manifest-path pkg/tbtc/signer/Cargo.toml formal_verification_` - `pkg/tbtc/signer/scripts/run_phase5_chaos_suite.sh` (all 6 scenarios passed) - `git diff --check` CI is authoritative for the TLA+ model and dependency-audit gates.
## Stack Rust signer review-fix stack 2 of 3. - Depends on: #4157 - Ultimate base: `extraction/frost-signer-mirror-2026-05-26` (#4005) - Follow-up: #4159 — startup load serialization Merge #4157 first, then retarget this PR to the extraction branch. ## What changed - Introduce a transparent `SecretHex` holder backed by `Zeroizing<String>` with redacted Debug output and zeroize-on-drop semantics. - Use it for DKG secret packages, confidential round-2 packages, and the long-lived native FROST key package signing share. - Preserve the existing JSON string wire shape and FFI ABI while avoiding independent unwiped Rust-owned secret string allocations. - Continue wiping decoded and serialized byte buffers and returned FFI buffers through their existing paths. ## Review finding addressed - P2: treat DKG package fields as secret-bearing types. Caller-owned FFI request memory remains the caller responsibility; Rust-owned request/result allocations and returned buffers now have explicit wipe paths. ## Verification - `cargo fmt --manifest-path pkg/tbtc/signer/Cargo.toml -- --check` - `cargo check --locked --manifest-path pkg/tbtc/signer/Cargo.toml --all-targets` - `cargo clippy --locked --manifest-path pkg/tbtc/signer/Cargo.toml --all-targets -- -D warnings` - DKG serde, Debug-redaction, zeroize-on-drop, distributed-DKG persistence, and FFI round-trip tests - `cargo test --locked --manifest-path pkg/tbtc/signer/Cargo.toml` - `git diff --check` The TLA+ runner and `cargo-deny` are unavailable locally; CI remains authoritative for those gates.
## Stack Rust signer review-fix stack 1 of 3. - Base: `extraction/frost-signer-mirror-2026-05-26` (#4005) - Follow-up: #4158 — DKG secret zeroization - Final: #4159 — startup load serialization ## What changed - Require Aggregate attempt IDs to be canonical SHA-256 hex, and bind fixed-size Aggregate authorization to the validated attempt, signing package, and taproot root. - Allow the elected coordinator to aggregate a validated attempt without requiring that coordinator to be part of the frozen signing subset. - Keep consumed markers readable by the immediately previous schema-1 binary, and pin a retired session for the full unlocked Aggregate operation. - Reclaim completed per-message sessions through bounded retirement while keeping every persisted schema-1 snapshot within the legacy total `TBTC_SIGNER_MAX_SESSIONS` limit. - Reserve new session slots by transactionally evicting the oldest eligible retired tombstone; protect pending and in-flight Aggregate sessions, and restore evicted replay state after pre-replacement Build/DKG/Open failures. - Persist the first per-message Open binding before success, and make Abort plus full or partial TTL expiry crash-durable. Post-replacement uncertainty remains fail-closed behind a repair marker. - Stage retirement before registering a post-rename Aggregate repair, so either the exact retry or an unrelated full-state writer durably covers completion and retirement before clearing pending protection. - Compact and immediately rewrite oversized intermediate schema-1 state during load so emergency rollback remains available. ## Review findings addressed - P1: reclaim per-message sessions after completion. - P2: validate Aggregate attempt IDs before persistence. - P1: allow non-signing coordinators to aggregate. - P1: preserve consumed markers across binary rollback. - P2: pin sessions while aggregation is in flight. - P1: preserve the previous total-session bound on disk. - P2: make Abort-driven retirement crash-durable. - P2: retire the session after an Aggregate repair. Retired per-message tombstones use only the unoccupied portion of the shared legacy-compatible total session budget. Live wallet/DKG sessions are never classified as retireable. ## Verification - `cargo fmt --manifest-path pkg/tbtc/signer/Cargo.toml -- --check` - `cargo check --locked --manifest-path pkg/tbtc/signer/Cargo.toml --all-targets` - `cargo clippy --locked --manifest-path pkg/tbtc/signer/Cargo.toml --all-targets -- -D warnings` - `cargo test --locked --manifest-path pkg/tbtc/signer/Cargo.toml` (259 passed, 1 ignored; the ignored multiprocess helper passes in its child process; 28 binary and 1 integration test passed) - `cargo test --locked --manifest-path pkg/tbtc/signer/Cargo.toml formal_verification_` - `pkg/tbtc/signer/scripts/run_phase5_chaos_suite.sh` (all 6 scenarios passed) - `git diff --check` CI is authoritative for the TLA+ model and dependency-audit gates.
## Stack 1 of 3. Base: `extraction/frost-signer-mirror-2026-05-26` (#4005). Next: #4161. ## Summary - Normalize one-component signer state paths to `.` for directory creation, fsync, and corrupt-backup enumeration. - Make completed canary rollback retries true no-ops for rollout state, config version, metrics, and promotion evidence. - Repair uncertain post-rename directory durability on a restarted rollback retry without rewriting the state file; keep fresh missing-state no-ops side-effect free. ## Review findings addressed - P1: bare state paths used an empty parent for directory operations. - P2: completed canary rollback retries were not idempotent. ## Validation - `cargo test --locked --manifest-path pkg/tbtc/signer/Cargo.toml` on this branch tip: 270 library tests passed, 1 ignored; 28 admission-checker tests passed; 1 integration test passed. - Fault-injection regressions cover pre/post-rename behavior, restarted retry repair, and no state rewrite on idempotent retry.
## Stack 2 of 3. Parent: #4160. Next: #4162. ## Summary - Reject unknown top-level fields when deserializing `AdmissionPolicyV1`. - Keep supported policy files compatible while turning misspelled security controls into explicit input errors instead of omitted limits. - Add a malicious typo regression and a supported-field positive control. ## Review finding addressed - P2: unknown admission-policy fields could silently disable enforcement and fail open. ## Security invariant A policy field that the checker does not recognize cannot silently alter or weaken admission behavior. ## Validation - `cargo test --locked --manifest-path pkg/tbtc/signer/Cargo.toml` on this branch tip: 270 library tests passed, 1 ignored; 30 admission-checker tests passed; 1 integration test passed. - The real checker rejects a misspelled `max_operator_per_provider` field and accepts the shipped policy sample.
## Stack 3 of 3. Parent: #4161. ## Summary - Track each live interactive signing member from its last accepted activity using monotonic `Instant` state instead of wall-clock Open time. - Refresh activity for exact Open retries, accepted Round1 calls, and retry-preserving Round2 failures; rejected traffic does not extend lifetime. - Add a forward-only test clock and regressions for active-at-boundary attempts, idle siblings, invalid requests, retry-preserving failures, expiry, and reset behavior. ## Review finding addressed - P2: interactive inactivity TTL was measured from Open and could sweep an attempt used moments earlier. ## Lifecycle invariant Only accepted or retry-preserving member activity extends the TTL; successful terminal operations and post-replacement failures still retire the nonce handle. ## Validation - `cargo test --locked --manifest-path pkg/tbtc/signer/Cargo.toml`: 273 library tests passed, 1 ignored; 30 admission-checker tests passed; 1 integration test passed. - `cargo check --locked --manifest-path pkg/tbtc/signer/Cargo.toml --all-targets`. - `cargo clippy --locked --manifest-path pkg/tbtc/signer/Cargo.toml --all-targets -- -D warnings`. - `cargo fmt --manifest-path pkg/tbtc/signer/Cargo.toml -- --check` and `git diff --check`. - `pkg/tbtc/signer/scripts/run_phase5_chaos_suite.sh`: all 6 fault-injection scenarios passed.
Summary
Lands
pkg/tbtc/signer/, the Rust crate behindlibfrost_tbtc: the FROST threshold-Schnorr signing engine for tBTC v2's migration from tECDSA to Taproot (BIP-340/341) wallets. The Go client consumes it over a versioned cgo/JSON FFI. The crate implements the per-participant distributed FROST DKG rounds, interactive ROAST signing sessions with member-custodied nonces, signature-share verification with attributable blame, Taproot transaction assembly under a signing-policy firewall, and encrypted signer-state persistence — plus the formal models, cross-language vectors, and CI gates that guard all of it.Two properties define the current surface. Signing is interactive-only: the transitional "coarse" one-shot signing path that earlier revisions of this branch carried (
frost_tbtc_run_dkg,frost_tbtc_start_sign_round,frost_tbtc_finalize_sign_round,frost_tbtc_generate_nonces_and_commitments,frost_tbtc_sign_share,frost_tbtc_aggregate) has been deleted. Removing exported symbols is an incompatible contract change, so the structured version reported byfrost_tbtc_abi_versionis now ABI 2.0 and Go bridges fail closed against an incompatible library. Key generation is a real distributed DKG:dkg_part1/2/3plus gated key-package persistence; the dealer-style bootstrap path is gone from the exported surface and is rejected outright under the production profile.This PR is self-contained: nothing in keep-core consumes the crate yet (the cgo bridge and node wiring live in #3866), so it can land independently and first.
Why this lives in keep-core
Per extraction plan v38 section 3.1:
Provenance
The initial import was extracted from
tlabs-xyz/tbtc:feat/frost-schnorr-migrationat frozen signed tagfrost-extraction-source-v1(commit52389bd5cccb5daeef195671feb7ca46be6e2f37; manifest: https://github.com/tlabs-xyz/tbtc/blob/frost-extraction-source-v1/extraction/frost-extraction-source-manifest.json). That tag audits the initial import only. Since then, all signer development has happened inthreshold-network/keep-core: this branch now carries ~200 commits, almost all landed through individually reviewed sub-PRs merged into it (e.g. #4011, #4018, #4028, #4031, #4036, #4051–#4055, #4062, #4068, #4077, #4098, #4104, #4111–#4114, #4123–#4129, #4136, #4137). keep-core is the source of truth for the signer.Scope
FFI contract and ABI (
src/lib.rs,src/ffi.rs,src/api.rs,include/frost_tbtc.h)frost_tbtc_free_buffer); FFI buffers are zeroized and the production panic hook never reflects raw panic payloads across the boundary.frost_tbtc_abi_versionreturns a structured{abi_major, abi_minor}contract version with documented bump rules — currently 2.0 after the coarse-path deletion.frost_tbtc_init_signer_config(TBTC_SIGNER_*knobs), validated fail-closed: an unknown profile or degenerate signing window is fatal.Distributed DKG (
engine/dkg.rs, persistence gates inengine/persistence.rs/engine/provenance.rs)dkg_part1/2/3per-participant round functions overfrost-secp256k1-tr(pinned to the 3.0.0 final release).persist_distributed_dkg_key_packageaccepts a completed distributed-DKG key package as signing material only behind provenance, admission-policy, and operator-quarantine gates, with participant-count and canonical-ID validation, and verifies the signing share derives to its public share before accepting it.Interactive ROAST signing (
engine/interactive.rs,engine/roast.rs,engine/verify_share.rs,engine/frost_ops.rs)(session_id, attempt_id, member_identifier)with durable consumption markers; multi-seat operators get member-keyed session state.interactive_aggregateself-verifies the tweaked (key-path or script-path) signature, is idempotent via completion markers bound to the message and taproot root, and emits candidate-culprit blame for invalid shares.verify_signature_sharebacks the Go-side Round2 share verifier, including tweaked-root equivalence.derive_interactive_attempt_contextgives the host a canonical attempt-context derivation so session ids stay in contract.go_math_rand.rspins bit-exact Gomath/randparity).Taproot transactions and signing policy (
engine/transaction.rs,engine/policy.rs)build_taproot_txassembles validated unsigned Taproot transactions from provided inputs/outputs.State and secret-material hardening (
engine/state.rs,engine/persistence.rs,engine/audit.rs,engine/telemetry.rs,src/bin/admission_checker.rs)admission_checkerbinary plus sample policy JSONs for operator-side admission validation.Formal verification and vectors (
docs/formal/models/,scripts/formal/,tests/,test/vectors/,testdata/)formal_verification_invariant test suite.CI (
.github/workflows/tbtc-signer-formal.yml)cargo fmt --check,cargo clippy --all-targets -- -D warnings,cargo test, all with--locked), Signer dependency audit (blocking cargo-deny RustSec advisory gate), Signer formal invariants, and TLA model checks. Actions are pinned to commit SHAs with checkout credential persistence disabled.Docs (
pkg/tbtc/signer/docs/)Misc
pkg/bitcoin/electrum: refresh the Fulcrum integration-test endpoint (incidental CI fix; the only change outsidepkg/tbtc/signer/and its workflow).Validation
cargo fmt -- --check,cargo clippy --all-targets -- -D warnings,cargo test,cargo test formal_verification_,scripts/formal/run_tla_models.sh).3e87d011…) → mint → redemption (86c978c6…) → second distributed DKG (with on-chain result submit/challenge/approve on the node side) → FROST→FROST moving funds (f3b951b0…).Relationship to companion PRs
libfrost_tbtcand fails closed on an ABI mismatch. DKG result digests are computed on both sides and checked for parity; the node aggregates the shares this signer produces. The two PRs are complementary; this one is unconsumed until feat(tbtc/node): FROST/ROAST Go node — distributed DKG, interactive signing loop, Taproot wallet lifecycle #3866 lands, so it can merge first.revealTaprootDepositP2TR deposits, full multi-mode BIP-341 key-path sighash fraud coverage (consuming the same fraud-vector file this PR ships), P2TR redeemer addresses, and SDK Taproot deposit support incl. testnet4.These three PRs comprise the FROST extraction into the canonical repos (plan v38).
Review notes
The diff is +32,305/−2 across 77 files, but it slices cleanly:
include/frost_tbtc.h(102 lines), thensrc/api.rsandsrc/lib.rs— the exported symbols, JSON envelopes, error codes, and the ABI versioning rules.engine/mod.rs,engine/lifecycle.rs,engine/state.rs,engine/codec.rs.engine/dkg.rsplus the persistence/provenance gates inengine/persistence.rsandengine/provenance.rs.engine/interactive.rs,engine/roast.rs,engine/verify_share.rs,engine/frost_ops.rs.engine/policy.rs,engine/init_config.rs,engine/config.rs,engine/telemetry.rs,engine/audit.rs,src/bin/admission_checker.rs.engine/tests.rs(~8.9k lines, organized by endpoint),tests/p2tr_signature_fraud_vectors.rs, and the vector/corpus JSON.Roughly 9k lines are engine logic, ~9.5k are tests, and the remainder is
Cargo.lock, docs, vectors, and CI. Nearly all commits landed via individually reviewed sub-PRs merged into this branch, so reviewing sub-PR-by-sub-PR is a practical alternative to reviewing the squashed diff.