From 41f99576308d192526093a39718fff842692d13c Mon Sep 17 00:00:00 2001 From: craigraw Date: Thu, 5 Mar 2026 18:02:52 +0200 Subject: [PATCH] BIP392: Silent Payment Output Script Descriptors (#2047) * Add sp() output descriptor format for BIP352 Silent Payments * Update headers and remove space after comma in descriptors * Add label ranges with examples * Update with assigned number and adjust preamble for BIP3 * BIP392: Add table entry to README * Add two argument key expression form and remove birthday and label arguments * Add BIP392 sp() descriptor to BIP380 script expressions table * Add sp() descriptor to BIP390 allowed expressions and add musig() example to BIP392 * Add changelog and version header to BIP390 --- README.mediawiki | 7 +++ bip-0380.mediawiki | 3 ++ bip-0390.mediawiki | 10 +++- bip-0392.mediawiki | 114 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 bip-0392.mediawiki diff --git a/README.mediawiki b/README.mediawiki index b0cea7dc..55580ee0 100644 --- a/README.mediawiki +++ b/README.mediawiki @@ -1381,6 +1381,13 @@ users (see also: [https://en.bitcoin.it/wiki/Economic_majority economic majority | Informational | Draft |- +| [[bip-0392.mediawiki|392]] +| Applications +| Silent Payment Output Script Descriptors +| Craig Raw +| Specification +| Draft +|- | [[bip-0431.mediawiki|431]] | Applications | Topology Restrictions for Pinning diff --git a/bip-0380.mediawiki b/bip-0380.mediawiki index 3f113f2a..e6311224 100644 --- a/bip-0380.mediawiki +++ b/bip-0380.mediawiki @@ -334,4 +334,7 @@ This Table lists all available Script expressions and the BIPs specifying them. |- | musig(KEY, KEY, ..., KEY) | [[bip-0390.mediawiki|390]] +|- +| sp(KEY), sp(KEY, KEY) +| [[bip-0392.mediawiki|392]] |} diff --git a/bip-0390.mediawiki b/bip-0390.mediawiki index 2daed4d2..a6b5526a 100644 --- a/bip-0390.mediawiki +++ b/bip-0390.mediawiki @@ -7,6 +7,7 @@ Type: Informational Assigned: 2024-06-04 License: CC0-1.0 + Version: 0.2.0 Requires: 380, 328 @@ -33,8 +34,8 @@ and [[bip-0389.mediawiki|BIP-389]]. ===musig(KEY, KEY, ..., KEY)=== -The musig(KEY, KEY, ..., KEY) expression can only be used inside of a tr() or -rawtr() expression as a key expression. It additionally cannot be nested within another musig() +The musig(KEY, KEY, ..., KEY) expression can only be used inside of a tr(), rawtr() +or sp() expression as a key expression. It additionally cannot be nested within another musig() expression. Participant public keys may be repeated. The aggregate public key is produced by using the KeyAgg algorithm on all KEYs specified in the expression after performing all specified derivation. As with script expressions, KEY can contain child derivation specified by @@ -118,6 +119,11 @@ are likely to be familiar with them. The reference implementation is available in Bitcoin Core [[https://github.com/bitcoin/bitcoin/pull/31244|PR #31244]]. +==Changelog== + +* __0.2.0__ (2026-03-04) - Allow musig() inside sp() expressions. +* __0.1.0__ (2025-12-08) - Allow musig() inside rawtr() expressions. + ==Acknowledgements== Thanks to Pieter Wuille, Andrew Poelstra, Sanket Kanjalkar, Salvatore Ingala, and all others who diff --git a/bip-0392.mediawiki b/bip-0392.mediawiki new file mode 100644 index 00000000..c1424bfd --- /dev/null +++ b/bip-0392.mediawiki @@ -0,0 +1,114 @@ +
+  BIP: 392
+  Layer: Applications
+  Title: Silent Payment Output Script Descriptors
+  Authors: Craig Raw 
+  Status: Draft
+  Type: Specification
+  Assigned: 2026-02-06
+  License: BSD-2-Clause
+  Discussion: https://groups.google.com/g/bitcoindev/c/bP6ktUyCOJI
+  Requires: 341, 350, 352, 380
+
+ +==Abstract== + +This document specifies sp() output script descriptors for silent payments. +sp() descriptors take silent payment key material and describe P2TR outputs when combined with sender input public keys as defined in BIP352. + +==Copyright== + +This BIP is licensed under the BSD 2-clause license. + +==Motivation== + +BIP352 defines silent payments, a protocol for static payment addresses without on-chain linkability. +This descriptor provides a standardized way to represent silent payment outputs within the output descriptor framework, enabling wallet interoperability and backup/recovery using existing descriptor-based infrastructure. + +==Specification== + +A new top level script expression is defined: sp(). + +===Key Expressions=== + +Two new key expression types are defined for use with sp() descriptors: + +====spscan==== + +The spscan key expression encodes the scan private key and spend public key. +It is a [https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki Bech32m] encoding of: +* The human-readable part "spscan" for mainnet, "tspscan" for testnets +* The data-part values: +** The character "q", to represent silent payments version 0 +** The payload: ser256(bscan) || serP(Bspend) + +====spspend==== + +The spspend key expression encodes both the scan and spend private keys. +It is a [https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki Bech32m] encoding of: +* The human-readable part "spspend" for mainnet, "tspspend" for testnets +* The data-part values: +** The character "q", to represent silent payments version 0 +** The payload: ser256(bscan) || ser256(bspend) + +Note: The serialization of ser256(p) and serP(P) follows the definition in BIP352. + +===sp()=== + +The sp(KEY) or sp(KEY,KEY) expression can only be used as a top level descriptor. + +sp(KEY) takes a single key expression as an argument, which must be either an spscan or spspend encoded key, optionally with key origin information. +If included, the key origin information specifies the fingerprint and derivation path to the depth from which the scan and spend keys are derived using the child paths recommended in BIP352 (1h/0 for scan, 0h/0 for spend). + +sp(KEY,KEY) takes two key expressions. +The first key expression represents the scan key and must be a single private key (e.g. a WIF compressed private key or xprv extended private key). +The second key expression represents the spend key and may be any key expression as defined in BIP380 or other key expression BIPs (e.g. musig() as defined in BIP390) that represents a single key, public or private. +Note however that uncompressed keys are not allowed under any sp() expression, as BIP352 only permits compressed public keys. + +When combined with sender input public keys, the descriptor produces P2TR output scripts describing silent payments made to wallets represented by the key expression(s). + +The output scripts produced are BIP341 taproot outputs as specified in BIP352. + +==Examples== + +Valid descriptors: + +* sp(spscan1q...) - Using spscan encoded key (watch-only) +* sp([deadbeef/352h/0h/0h]spscan1q...) - With key origin +* sp(spspend1q...) - Using spspend encoded key (full wallet) +* sp(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600) - WIF scan key with compressed public spend key (watch-only) +* sp([deadbeef/352h/0h/0h]xprv.../0h,xpub.../0h) - Extended private scan key with extended public spend key (watch-only) +* sp([deadbeef/352h/0h/0h]xprv.../0h,xprv.../0h) - Extended private keys for both scan and spend (full wallet) +* sp(L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1,musig(03dff1d77f2a671c5f36183726db2341be58feae1da2deced843240f7b502ba659,023590a94e768f8e1815c2f24b4d80a8e3149316c3518ce7b7ad338368d038ca66)) - WIF scan key with MuSig2 aggregate spend key (watch-only) + +Invalid descriptors: + +* sp() requires at least one key expression +* sp(xpub...) single argument form requires spscan or spspend encoded key +* sp(xpub...,xpub...) two argument form requires private scan key (e.g. WIF or xprv) +* sp(spscan1q...,spscan1q...) two argument form requires single key expressions +* sp(5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss,0260b2003c386519fc9eadf2b5cf124dd8eea4c4e68d5e154050a9346ea98ce600) uncompressed private key +* sh(sp(spscan1q...)) sp() is top level only +* wsh(sp(spscan1q...)) sp() is top level only + +==Usage Notes== + +For watch-only wallets, use spscan encoding or the two argument form with a public spend key. +For full wallets that can both scan and spend, use spspend encoding or the two argument form with a private spend key. + +When using the two argument form, the scan key must be private (e.g. WIF or xprv) since scanning requires the private scan key. + +==Backwards Compatibility== + +sp() descriptors use the format and general operation specified in BIP380. +As this is a wholly new descriptor, it is not compatible with any prior implementation. +The scripts produced are BIP341 taproot outputs, making them indistinguishable from other taproot outputs on-chain. + +==Reference Implementation== + +TBD + +==Test Vectors== + +TBD +