# NOTES: FROST Signing Using Trusted Dealer & bdk-cli ## High-Level Demo Description - The demo workflow shows, end‑to‑end, how to spend Taproot (P2TR) Bitcoin on a private regtest network using a 2‑of‑3 FROST threshold signature. - Standard tooling (Bitcoin Core, `bdk-cli`) handles wallet management and PSBT construction - The `zcash-frost-tools` libraries, extended to support `secp256k1` and Taproot handle the multi-party signing. - Two tiny Rust helpers bridge the current gaps in `bdk-cli` for Taproot sighash extraction and PSBT signature injection. The result is a fully valid, single‑signature Taproot transaction that any Bitcoin node will accept. The current demonstration uses a trusted dealer which generates a private key, splits it, and distributes the shares to the particpants. Future work will support "Distributed Key Generation" (DKG), where the private key used to sign will never exist in one place. ## Outline of the Demo ### One‑Time Environment Setup * **Install FROST utilities** (`trusted-dealer`, `coordinator`, `participant`) from the `zcash-frost-tools` repo’s `taproot-tweak` branch. * **Launch a fresh Bitcoin Core node** in *regtest* mode, with RPC enabled, and mine 101 blocks to unlock coinbase rewards. * **Write two helper binaries** * `sighash-helper` – reads a PSBT and prints the 32‑byte Taproot key‑path sighash. * `psbt-sig-attach` – pastes a raw 64‑byte Schnorr signature back into input 0 of a PSBT. ### Demo Flow 1. **Regular Wallet (single signer)** * Generate a BIP‑86 descriptor, create a wallet with `bdk-cli`, and mine funds into it (50 BTC). 2. **FROST Wallet (2‑of‑3 quorum)** * Use `trusted-dealer` to create three key shares and an aggregate verifying key. * Build watch‑only Taproot descriptors from the aggregate key and obtain the first FROST address. 3. **Fund the Quorum** * Send 1 BTC from the regular wallet to the FROST address; mine one block to confirm. 4. **Prepare the Spend** * Ensure the FROST wallet holds exactly one UTXO (the 1 BTC just received). * Construct a one‑input, one‑output PSBT that pays 0.5 BTC back to a new address in the regular wallet. 5. **Extract the Message to Sign** * Run `sighash-helper` on the PSBT to obtain the Taproot key‑path sighash (32 bytes). 6. **Run the FROST Ceremony** * **Coordinator** starts with threshold 2, the sighash, and waits for commitments. * **Participants 1 & 2** send nonce commitments, receive the signing package, approve the message, and return their signature shares. * **Coordinator** combines the two shares into a complete Schnorr signature (`sig.raw`). 7. **Finalize the Transaction** * Hex‑encode the signature and inject it into the PSBT with `psbt-sig-attach`. * Call `bdk-cli finalize_psbt` to strip the PSBT wrapper, then `bdk-cli broadcast` to publish the transaction. 8. **Verification** * Mine one more block, sync the regular wallet, and observe its balance rise by exactly 0.5 BTC, confirming the Taproot spend signed by the FROST quorum. --- **Key Take‑Aways** * **Threshold Control, Single Signature** – Two of the three participants jointly produce a *single* Taproot Schnorr signature; on‑chain it is indistinguishable from a normal key spend. * **No Trusted Dealer at Spend Time** – After the initial share creation, private keys never co‑reside; security is preserved throughout. * **Minimal Extras** – Only two helper tools were needed because `bdk-cli` has not yet exposed certain Taproot PSBT operations; everything else used is third-party software. * **Regtest Proven** – The demo mines, broadcasts, and confirms transactions in a self‑contained regtest, proving the workflow without touching testnet or mainnet coins. ## Why we need two Rust helper functions to complete the workflow The `bdk-cli` tool does not provide interfaces for two critical steps of the demonstrated FROST workflow: - A way to extract a sighash from a PSBT - A way to attach a signature (signed sighash) to a PSBT before finalization Because of this, the demo workflow gives instructions for compiling and installing the `sighash-helper` and `psbt-sig-attach` Rust helpers, which perform these functions. ## Why Does the Taproot Tweak Exist? Taproot outputs hide a little secret in plain sight. Instead of publishing either a bare key **or** a hash of a spending script, they publish a *tweaked key*—the sum of an ordinary x-only public key **P** and a hash-derived point **H(P||merkle\_root)·G**. That tweak accomplishes three things at once. First, it **commits to any optional script paths without revealing them**. The merkle root of the script tree is inside the hash that produces the tweak, so if the spender later chooses a script path they can prove it was pre-committed; if they don’t, nothing about the on-chain output hints that scripts existed at all. ([bips.dev][1], [learnmeabitcoin.com][2]) Second, because the commitment is folded into a point on the curve, the final output still looks exactly like an ordinary single-signature key. That uniform appearance tightens privacy and fungibility by denying chain analysts an easy way to distinguish “complex” wallets from simple ones, while also shrinking block weight—only a single 32-byte key goes into the locking script. ([Medium][3], [Medium][4]) Third, the tweak is **linear**: every private-key share holder can add the same scalar **t** to their secret, and when their shares are combined the result matches the on-chain tweaked key. That property is what lets threshold-signature schemes like FROST work over Taproot without leaking the script commitment or needing a trusted dealer; add-then-sum is the same as sum-then-add. ([DEV Community][5]) In short, the Taproot tweak was introduced to bind optional scripts to a key in a way that preserves privacy, cuts fees, and keeps the algebra simple enough for multisig and threshold systems to remain first-class citizens of the protocol. [1]: https://bips.dev/341/?utm_source=chatgpt.com "BIP 341: Taproot: SegWit version 1 spending rules" [2]: https://learnmeabitcoin.com/technical/upgrades/taproot/?utm_source=chatgpt.com "Taproot | Technical Explanation - Learn Me A Bitcoin" [3]: https://medium.com/coinmonks/on-bitcoins-schnorr-signature-algorithm-and-taproot-script-and-witness-sizes-fe4d1e6591a7?utm_source=chatgpt.com "On Bitcoin's Schnorr signature algorithm and Taproot script and ..." [4]: https://medium.com/interdax/what-is-taproot-and-how-will-it-benefit-bitcoin-5c8944eed8da?utm_source=chatgpt.com "How will Taproot Benefit Bitcoin? | Interdax Blog - Medium" [5]: https://dev.to/eunovo/more-on-taproot-41g8?utm_source=chatgpt.com "More on Taproot - DEV Community" ## Taproot‑Tweak Branch — Lessons Learned * **Defaults Beat Dials**  Taproot intent is obvious when the ciphersuite is `secp256k1‑tr`; extra flags only clutter UX. * **One Truth for Keys**  Public and secret material must be tweaked together—or not at all—otherwise signatures fail. * **Leverage Proven Primitives**  Rely on `aggregate_with_tweak()` from the upstream crate instead of re‑implementing BIP‑341 math. * **Parity Is Non‑Negotiable**  Enforce even‑Y internal keys at generation time to avoid subtle x‑only edge‑cases. ## Future Work - Remove `--internal-key` option; was added for testing during development and no longer necessary - Make sure that FROST works for straight BIP-340 Schnorr signing - Remove outdated tests and docs, restore a couple config files that were removed since the branch diverged