Skip to content

docs: Miniscript coordinator pattern reference (draft) - #4

Draft
Vibherpunk wants to merge 2 commits into
KeeperCommunity:mainfrom
Vibherpunk:draft/miniscript-coordinator-pattern
Draft

Vibherpunk wants to merge 2 commits into
KeeperCommunity:mainfrom
Vibherpunk:draft/miniscript-coordinator-pattern

Conversation

@Vibherpunk

@Vibherpunk Vibherpunk commented Oct 7, 2026 •

Copy link
Copy Markdown

Description

Summary

Demonstrates the coordinator-side Miniscript approach for hardware wallets that don't natively understand Miniscript (Satochip, TAPSIGNER).

The coordinator (wallet app) parses the Miniscript descriptor, determines the spending path, and constructs the PSBT with the correct witness script. The hardware device just signs the sighash digest — no policy understanding required on the device.

This keeps simple, durable hardware usable in Miniscript wallets instead of restricting Miniscript to devices that fully understand the policy.

What's included (Reference Only)

This initial draft includes only Rust reference files adapted from Bitme, to aid discussion of the pattern:

  • docs/miniscript-reference/descriptor-reference.rs
  • docs/miniscript-reference/invariants-reference.rs
  • docs/miniscript-reference/coordinator-pattern.md
  • docs/miniscript-reference/README.md

Note on Bitme vs. Keeper Policies: The provided Rust references and the sequence diagram in coordinator-pattern.md encode Bitme's specific policy (exactly one immediate path, older(N) timelocks, server-side hold/veto). These are explicitly marked as Bitme-only reference material. Any implementation for Keeper will strictly use Keeper's actual wallet policy (e.g., 2-of-3 base + Inheritance Key paths).

Explicit Inheritance Boundary

It is important to emphasize that the Inheritance Key and the conditions for its spending path belong purely in the wallet's Miniscript policy. They are not an Inheritance Key approval or timelock implemented by SigningServer. The server's notification, delay, and veto mechanics govern only the server's own signature. The server participates in a spend only if the chosen path uses its key.

Planned Follow-up Work (Server-Side Scope)

The actual implementation will be focused entirely on missing server cases (app-side coordinator/Satochip implementation will be a separate app PR).
Since SigningServer already has Miniscript descriptor handling and PSBT address checks, the planned TypeScript follow-up work will include:

  • Focused tests for any missing server cases when dealing with Miniscript descriptors (such as independently recomputing/verifying witness_script and witness_utxo from a server-owned descriptor to ensure the server isn't simply trusting the PSBT's metadata).
  • src/miniscript/descriptor.ts and src/miniscript/invariants.ts: To perform semantic analysis and formal policy checks (ensuring no single key can spend alone, exactly one immediate path if applicable, etc.) for Keeper's actual policy.
  • tests/miniscript.test.ts: Runnable invariant tests using Keeper's policy.

The coordinator pattern

From Bitme's approach:

  1. Coordinator parses the Miniscript descriptor for the wallet
  2. Coordinator determines which spending path applies
  3. Coordinator constructs the PSBT with the correct witness_script for that path
  4. Hardware device signs the sighash digest (a hash — no Miniscript understanding needed)
  5. Coordinator collects signatures and finalizes the transaction

References

  • Technique adapted from TDH-Labs/Bitme
  • Related discussion with maintainer on Miniscript coordinator approach

Open questions for maintainer (before full implementation)

  1. Miniscript library: Which JS/TS library should we use? Options:

    • bitcoinjs-lib (has partial Miniscript support)
    • Dedicated Miniscript TS library (if one exists and is audited)
    • FFI to rust-miniscript via WASM?
  2. Directory placement: New src/miniscript/ or inside existing src/wallet/?

Adds reference material for the coordinator-side Miniscript approach,
adapted from TDH-Labs/Bitme. Includes:

- Formal invariant tests (generalized from Satochip to generic hardware)
- Descriptor construction pattern
- Coordinator flow documentation

This is reference material for discussion, not the TypeScript implementation.
See docs/miniscript-reference/README.md for details.

antuz123 commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Thanks for opening this as a draft. Before implementation, could you please address these points?

  1. Define the server-side scope. The Keeper wallet app should choose the Miniscript spending path, build/finalize the PSBT, and keep Satochip signing-only. Since this PR is in SigningServer, please identify the specific server behavior or failing case you want to change here. The server already has Miniscript descriptor handling and PSBT address checks, so a focused test of any missing server case would help. Please keep the app-side coordinator/Satochip implementation as a separate app follow-up.

  2. Keep the inheritance boundary explicit. The Inheritance Key and the conditions for its spending path belong in the wallet's Miniscript policy. They are not an Inheritance Key approval or timelock implemented by SigningServer. Server notification, delay, and veto govern only the server's own signature; the server participates in a spend only if the chosen path uses its key. Please state this distinction in the proposal.

  3. Separate Bitme examples from Keeper policy. descriptor-reference.rs and invariants-reference.rs still encode Bitme's Hardware + Server immediate path, older(N) paths, and the assumption of exactly one immediate pair. coordinator-pattern.md shows a concrete 15-minute server hold/veto flow. The PR description says Bitme's descriptor and server policy engine are out of scope. Please remove these examples from the proposed Keeper flow or mark them clearly in each file as Bitme-only reference material. Any implementation tests should use Keeper's actual wallet policy, including its Miniscript inheritance path.

  4. Make the description match this draft. The current diff adds four reference files, not the TypeScript modules and runnable tests listed under “What's included.” Please describe those as planned follow-up work. The proposed independent witness_script/witness_utxo verification from a server-owned descriptor also needs to be distinguished from current behavior and scoped separately if you want to pursue it.

@Vibherpunk

Copy link
Copy Markdown
Author

Thanks for the feedback! I've updated the PR description and added clear disclaimers to the reference files to address all four of your points. The scope, inheritance boundary, and distinction from the actual Keeper policy should be much clearer now.

antuz123 commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Thanks, Adam. The updated PR description and Bitme-only warnings make the reference scope clear.

Would you be interested in taking a focused Keeper-specific SigningServer implementation step in a separate PR? A good starting point would be one concrete missing server behavior for Keeper’s actual 2-of-3 Mobile + Hardware + Server policy, with the optional inheritance path defined in the wallet’s Miniscript policy: add a runnable TypeScript test that shows the gap, then make the smallest server change needed to pass it. Independent checking of PSBT script and UTXO data against the server-owned policy may be a candidate if a test demonstrates a gap in the current checks.

The wallet-app coordinator and hardware signing work are separate. Which first server case would you take?

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.

2 participants