Skip to content

wip(tbtc): ABI 3.5 inventory/state-witness consumers and signing readiness#4199

Draft
mswilkison wants to merge 5 commits into
feat/frost-schnorr-migration-scaffoldfrom
codex/frost-preauth-outbox-restored
Draft

wip(tbtc): ABI 3.5 inventory/state-witness consumers and signing readiness#4199
mswilkison wants to merge 5 commits into
feat/frost-schnorr-migration-scaffoldfrom
codex/frost-preauth-outbox-restored

Conversation

@mswilkison

Copy link
Copy Markdown
Contributor

Based on #3866. Draft — incomplete, opened to make the work reviewable and durable, not because it is ready.

Adds Go consumers for the Rust signer's ABI 3.5 inventory and state-witness symbols (see keep-core #4198), plus interactive-signing readiness checks wired into the node.

What is NOT done

Native inventory parsing is unfixed. The Rust keyGroup is a lowercase 66-character compressed SEC1 key. The parser must accept both valid 64-character x-only test keys and 66-character compressed keys via TaprootOutputKeyFromTBTCSignerKey, and require the resulting x-only key to equal walletID. Frozen vector to pin:

walletID = 11*32,  keyGroup = 02 + 11*32,  threshold 2, participants 3, epoch 0
public commitment = 33*32,  seat 1/3 commitments = 44*32 and 55*32
expected inventory commitment = bd6ec36fa27a57dd9926883bb2ff4dee7ececd28de940df7294f0e0f0dedd150

The state anchor is still an interface. It needs a concrete authenticated Read + CompareAndSwap service with a durable PostgreSQL schema, fresh nonce, store/protocol/trust-domain/operator/authority/client identity binding, signed responses with bounded ancestry verification, unknown-outcome recovery by readback, and rejection of stale, divergent, ahead, over-window or wrong-identity states. It must anchor every security-relevant native mutation before Round1 commitments or Round2 shares leave the process. An interface-only implementation is not acceptable for activation.

Casing asymmetry to verify against the Rust side: DurableStoreIdentityResult is snake_case; RetainedKeyPackageInventoryResult, StateWitnessProofRequest (deny_unknown_fields, maximumEntries is u16 bounded 1..=256) and StateWitnessProofResult are camelCase.

Verification performed

Only go build ./pkg/tbtc/... ./pkg/frost/... — succeeds. No test run, no cgo integration run, no cross-language vector check.

mswilkison and others added 4 commits July 21, 2026 14:54
…iness

Adds Go consumers for the Rust signer's ABI 3.5 inventory and state-witness
symbols, plus interactive-signing readiness checks wired into the node.

INCOMPLETE - committed to preserve the work, not because it is ready:

- Native inventory parsing is unfixed. The Rust keyGroup is a lowercase
  66-character compressed SEC1 key; the parser must accept both valid
  64-character x-only test keys and 66-character compressed keys via
  TaprootOutputKeyFromTBTCSignerKey, and require the resulting x-only key to
  equal walletID. Frozen vector to pin: walletID = 11*32, keyGroup = 02 + 11*32,
  threshold 2, participants 3, epoch 0, public commitment 33*32, seat 1/3
  commitments 44*32 and 55*32, expected inventory commitment
  bd6ec36fa27a57dd9926883bb2ff4dee7ececd28de940df7294f0e0f0dedd150.

- The read-only state anchor is still an interface. It needs a concrete
  authenticated Read + CompareAndSwap service with a durable PostgreSQL schema,
  fresh nonce, store/protocol/trust-domain/operator/authority/client identity
  binding, signed responses with bounded ancestry verification, unknown-outcome
  recovery by readback, and rejection of stale, divergent, ahead, over-window or
  wrong-identity states. It must anchor every security-relevant native mutation
  before Round1 commitments or Round2 shares leave the process. An
  interface-only implementation is not acceptable.

- Casing asymmetry to verify against the Rust side: DurableStoreIdentityResult
  is snake_case, while RetainedKeyPackageInventoryResult, StateWitnessProofRequest
  (deny_unknown_fields, maximumEntries is u16 bounded 1..=256) and
  StateWitnessProofResult are camelCase.

Verified only that `go build ./pkg/tbtc/... ./pkg/frost/...` succeeds. No test
run, no cgo integration run, no cross-language vector check.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012KZb3W6TwYtKTw1mb2sfpS
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e1827c6b-3162-4c5b-8677-ac26ff209c26

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/frost-preauth-outbox-restored

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Lockstep bump for the signer's ABI 3.5 -> 4.0 change (keep-core #4198).
Per this file's own rule, the Go constants and ci/frost-signer-pin.env move
together with the lib commit that provides them.

Under ABI 3, `durable_store_fingerprint` mixed the stable `.store-id` with the
parent directory's path string and inode, the filesystem device, and the
advisory lock file's inode — and that composite was the first field of every
state commitment. So deleting the zero-byte lock file, restoring the data
directory from backup at the same path, renaming it, or remounting where
st_dev is unstable made every committed record unverifiable and the signer
unstartable, with no in-band recovery: the failure is raised inside
StateFileLock::acquire, before the corruption policy can apply.

ABI 4.0 binds commitments to the stable `.store-id` alone. The path,
filesystem and lock fingerprints are still computed and still enforced at
open — they simply no longer enter any committed transcript. The symbol set
is unchanged, but the VALUES of existing wire fields differ, so an ABI-3
library must not be linked by this bridge.

  requiredTBTCSignerABIMajor    3 -> 4
  requiredTBTCSignerABIMinMinor 5 -> 0
  FROST_SIGNER_MIRROR_REF       6e0fa97 -> a5363e9

Minor 0 is the initial ABI-4 surface and carries forward every symbol added
through 3.5 under the v2 identity and transcript schemas.

Verified: go build ./pkg/frost/... ./pkg/tbtc/... clean;
go test ./pkg/frost/signing/ passes, including the contract-pin guard.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012KZb3W6TwYtKTw1mb2sfpS
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant