Tapscript & MuSig2 support, with a miniscript decoder and satisfier#535
Tapscript & MuSig2 support, with a miniscript decoder and satisfier#535odudex wants to merge 9 commits into
Conversation
|
@jgriffiths I changed the PR back to draft after spotting a few issues and opportunities for improvement. Could you let me know when you're about to start reviewing it? That way I can keep refining the implementation and improving the PR's conciseness and digestibility through small iterations, amending changes into the feature commit as I go. Once you start the review, I'll stop rewriting the commit(s) you're reviewing and propose any further changes as follow-up commits instead. |
Adds tr() descriptors with script paths: the WALLY_LEAF_VERSION_TAPSCRIPT constant, multi_a/sortedmulti_a tapscript fragments, taptree parsing with BIP-341 merkle-root/leaf hashing, tr() address derivation including the key-path tweak, and the taproot tree/leaf/control-block/key-enumeration accessor APIs. Includes the C and Python descriptor test suites. Co-authored-by: odudex <odudex@proton.me>
Adds a standalone miniscript decoder (miniscript_decode.{c,h}): a Script
tokenizer and recursive-descent decoder for all miniscript fragments
(pk_k/pk_h, hashes, timelocks, multi/multi_a, and_v/and_b, or_b/c/d/i,
andor, thresh, and the wrapper fragments), with stack-overflow and
non-minimal-push hardening. Relocates ms_node and the shared KIND_*
constants into descriptor_int.h so the new translation unit can share
them. Includes the C decoder tests and the BIP-379 differential vectors.
Also tightens the string parser's verify_or_b/verify_or_c to require
their canonical child types (TYPE_B/TYPE_V), matching the decoder and
the BIP-379 reference vectors.
Co-authored-by: odudex <odudex@proton.me>
Adds the witness satisfier (miniscript_satisfy.c): per-fragment satisfaction/dissatisfaction with non-malleable minimum-weight selection (satisfaction_best, or_b/c/d/i, andor, thresh with a DP sort) and a satisfy_node dispatch over the decoded tree, plus the ms_witness / ms_satisfaction structures and lifecycle helpers. Includes witness_weight overflow saturation, iterative tree traversal to bound stack usage, and the geometric-growth / move-not-copy / precomputed-weight optimizations. Exercised directly by the C satisfy tests. Co-authored-by: odudex <odudex@proton.me>
|
Hi @odudex now that the PR is composed of a few larger commits, I will be starting with the first commit and reviewing each one essentially independently. This means I will take that commit on its own into a local branch and review/change as needed, without considering the context of future commits (each commit needs to pass independent review and will be updated as needed without considering the potential fallout on following commits). At the earliest I will start with the first commit at the middle to end of next week. If it makes things easier, I can comment here when I have begun assessing each commit? If you want to merge back a change to a commit later than that one, then you can feel free to do so until the point that I comment here that I have started on it, at which point feel free to push new commits with a comment that it should be merged back to a given commit. For such mergeback commits I will manually make the change(s) needed while reviewing and it can be dropped when the commit in question is merged. Please let me know if the above approach isn't clear or doesn't work for you. In the meantime until I comment here that I have started, please feel free to merge back/force push changes at will, thanks. |
Perfect! I'll keep improving and force-pushing, prioritizing 1st commit, until you start reviewing it. Then I'll wait your feedback and adjust course accordingly. |
Adds the MuSig2 implementation (musig.c) over the secp256k1-zkp musig module: key aggregation, nonce generation and aggregation, the signing pipeline (nonce_process, partial_sign, verify, aggregate), and lifecycle helpers for the opaque keyagg-cache / nonce / session / partial-sig types, plus BIP-328 synthetic-xpub helpers and the language bindings. Enables the secp256k1 musig module in the build and routes a malformed parsed keyagg-cache/session through a non-aborting illegal-argument callback. Includes the BIP-327/328 vector and protocol test suites. The bindings are regenerated from the headers via tools/build_wrappers.py (also picking up wrappers for the earlier descriptor taproot APIs). The Python SWIG wrapper gains the opaque output-parameter typemaps that the Java wrapper already had, and a contrib test covering the full signing flow. Co-authored-by: odudex <odudex@proton.me>
Adds the musig() key expression to the descriptor parser (valid only as a taproot internal key or tapscript leaf key), a format_key_node helper for serializing key nodes, and the musig() introspection API (participant count and per-participant keys). This enables parsing and address derivation for tr(musig(...)) descriptors. Includes the musig() descriptor parsing / address-generation tests and the BIP-390 vectors.
Adds PSBT support for the new descriptor types. BIP-371 taproot: internal key, leaf scripts, merkle root and tap bip32 derivation fields; script-path sighash, signing and descriptor-based taproot population; and the finalizers (p2wsh, p2tr key/script path, multisig). BIP-373 MuSig2: participant pubkey, public-nonce and partial-sig fields with nonce generation, partial signing, aggregation and finalization, plus wally_psbt_populate_musig2_from_descriptor. Includes the PSBT, MuSig2-PSBT, BIP-373 interop and satisfier differential test suites. Co-authored-by: odudex <odudex@proton.me>
Adds fuzz_descriptor (descriptor-string parse, script/address generation and key introspection, network chosen from the input) and fuzz_psbt_musig2 (splices fuzz bytes into BIP-373 MuSig2 key-value pairs in a minimal PSBT frame, covering both the key-path and script-path compound key forms), with seed corpora for both. The PSBT parse fuzzer now also runs wally_psbt_finalize, reaching the script-to-miniscript decoder and satisfier with attacker-controlled scripts. Co-authored-by: odudex <odudex@proton.me>
Registers the musig module in the docs index and adds contrib/musig2_psbt_2of2.py, a complete runnable 2-of-2 key-path example: aggregation, both nonce/signing rounds via the PSBT MuSig2 helpers, finalization and BIP-340 verification against the tweaked output key. Adds the 1.5.5 changelog entries for the taproot, miniscript and MuSig2 additions. Co-authored-by: odudex <odudex@proton.me>
Includes musig.c and the miniscript decoder/satisfier in the single-file amalgamation build, gated on BUILD_STANDARD_SECP for the MuSig2 module.
This PR adds tapscript (taproot script-path) descriptors, a Script→miniscript decoder
and a witness satisfier, MuSig2 (BIP-327) signing, and the descriptor / PSBT plumbing to
use them end-to-end.
The bulk of this work was authored by @pythcoiner. My own contributions are some bug fixes,
hardening, the amalgamation build integration folded into the relevant commits and a rebase proposed in #533 .
Goals
tr()script-path spending: taptree parsing,multi_a/sortedmulti_afragments, BIP-341 merkle-root/leaf hashing, and thetree/leaf/control-block accessor APIs.
witness satisfier (covering tapscript).
and BIP-328 synthetic-xpub helpers over the secp256k1-zkp musig module.
musig()descriptors (BIP-390) —tr(musig(...))parsing, address derivation,and participant introspection.
finalization, wired up from descriptors.
consumers building with
-DBUILD_STANDARD_SECP(MuSig2 compiled out) still build clean.Review structure
The original development history (100+ commits) has been reorganized into 9
self-contained commits, each a coherent milestone with its own tests. The intent is
to make this reviewable and mergeable gradually. Each commit builds, passes its
tests, and can be assessed (or landed) on its own rather than as one monolithic diff.
descriptor: add taproot (tapscript) descriptor supporttr()script paths:multi_a/sortedmulti_a, taptree parsing & BIP-341 leaf/merkle hashing, script-path address derivation, tree/leaf/control-block accessorsminiscript: add Script-to-miniscript decoderminiscript: add miniscript satisfiermusig2: add MuSig2 (BIP-327) core APIdescriptor: add musig() key expressions (BIP-390)musig()as a taproot internal/leaf key,tr(musig(...))derivation, participant introspection API; BIP-390 vectorspsbt: add taproot (BIP-371) and MuSig2 (BIP-373) supportfuzz: add fuzzers for musig() descriptor and PSBT MuSig2 fieldsmusig()descriptor fuzz cases + seed corpusdocs: document the MuSig2 API and add a 2-of-2 PSBT examplebuild: add musig and miniscript sources to the amalgamationBUILD_STANDARD_SECPBIPs implemented
BIP-327 (MuSig2), BIP-328 (xpub for aggregate keys), BIP-341 (Taproot), BIP-371
(PSBT Taproot fields), BIP-373 (PSBT MuSig2 fields), BIP-379 (Miniscript),
BIP-390 (
musig()descriptors).Tests
This branch was integrated in Kern project, where tapscript is under tests.
Musig2 support is not currently being tested in a consumer project. I believe @pythcoiner is baking some ideas and can share a north for practical tests.