From mboxrd@z Thu Jan 1 00:00:00 1970 Delivery-date: Mon, 22 Dec 2025 13:14:24 -0800 Received: from mail-ot1-f60.google.com ([209.85.210.60]) by mail.fairlystable.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1vXnEU-0002wY-2G for bitcoindev@gnusha.org; Mon, 22 Dec 2025 13:14:24 -0800 Received: by mail-ot1-f60.google.com with SMTP id 46e09a7af769-7c7599a6f1fsf10132193a34.1 for ; Mon, 22 Dec 2025 13:14:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1766438056; x=1767042856; darn=gnusha.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-sender:mime-version :subject:references:in-reply-to:message-id:to:from:date:sender:from :to:cc:subject:date:message-id:reply-to; bh=Dc884x6IzFah/pDmW1Jju7Sw6jSkqD7XqGsi05FKcA8=; b=xwrEw8m1QPI9DAOjeVoPlsAARWgqLKjWLb3DMwGcP7ZaSKS54eSKt/3ccF3q54nXDw XcTRXq4pHQlJiMJw09RJCRZEC/F89y/sDuhHmYJyHUhiYE01X72BMSOHiOJ4Q+Zfs/gG K4/KQH9rmT3YJP23JotlsSt8Nldv3Z1logTCuuEtuVLHDcGl0YvEhfMGMMQVLquT/XbN MswN9aUGDQDiiaZEaf3QBQWogQ//y/RvZOorD0AYWQYPzioJJLSoQimB+luioZbVIR57 8N7cxzyh+PPErFareLQXBIsLmB7D40RS+cl3ITW/nN0sMeyWqmkL41zZ1D5FC+2GYdGM CKrw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1766438056; x=1767042856; darn=gnusha.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-sender:mime-version :subject:references:in-reply-to:message-id:to:from:date:from:to:cc :subject:date:message-id:reply-to; bh=Dc884x6IzFah/pDmW1Jju7Sw6jSkqD7XqGsi05FKcA8=; b=HGy54MzPVReTt3CNRfg2oJYTWzvv1p9tGdoBGrINkWiX89Dl4mozqK1jdnF9zzywwF /Xkx5mhUzlW79Z2H6LzuylsFICl/wqkTJogsphnRodAguI5pcbYvydtow7AfOZTHvC2m l4SKqBJuxeHzVzFrDuoiul+FsT0bqGaJBuH9v8TGT0nv9OuUhxjt/jkH2GiJFSsxxC5x WIIWwmYM5ju54CqTA+X/hgZNDtn4ChY9J5RDg6wS/nm/+floB18p7f7025mvI0tJuvKJ XsZbdMjlYL1B3mNc07d2rlQDV+wjTtm/ejjNBjs644FWVvIDSrryYPZpTwNgPi30Ngum 9niA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1766438056; x=1767042856; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-sender:mime-version :subject:references:in-reply-to:message-id:to:from:date:x-beenthere :x-gm-message-state:sender:from:to:cc:subject:date:message-id :reply-to; bh=Dc884x6IzFah/pDmW1Jju7Sw6jSkqD7XqGsi05FKcA8=; b=KBlnXLvedBDIZo2LM4x8pcfons0fqoCOwiESm9R3blqJ/csHTgV+TCnl9FYp7JyYYE W5Y2W4RkFLNrtKMn/7X9JVgNTyPdk5bPi9bx9Z2Hi9++nYFazc+OevmMvcv/VIaMNqUn IbkEn9qIK0VzuszHTQqg5WSYg51G/PmTlm2NEFOW412tAI/ivLBvyeGqCbg+lXoqJg0C qyjAexZI0Pm1u/OCHnqz2++V9fMqZlxZdD17RMReDwdVadN94zB0CnOlveKFZdVFwvP4 Pf5CHac4pHVkTgTPhX7MDr7civ8yml4Wjfgq+QrYCJ7EdC1ZFkA4W7Vx/s+IOBNKfyQf gn9g== Sender: bitcoindev@googlegroups.com X-Forwarded-Encrypted: i=1; AJvYcCXpn/JYyJXBb4JA4XQOfSpOlIG1OaWLvDp1ryei2zw5lWAMuAhx/eO2w+r/2FGhm3eBRMraQ1uSU94e@gnusha.org X-Gm-Message-State: AOJu0YzFwQ0C5IZ/eXavG0iu5ZQS4gZrjINbh0XdB+BfxtuRM1A1j70d zN+gMycDW35Eg9pbhMzBy+4/DkAC8BZ0HzPTYggLTihnQ4PWZOKLFqMT X-Google-Smtp-Source: AGHT+IG5LU9d7643NFV7RlfPA9Z67WW0CTkYtY1LkR4QX/ijwwQWGA1Ui4Ft7FjR5+5qy62lV/HGgQ== X-Received: by 2002:a05:6830:44a5:b0:771:5ae2:fce0 with SMTP id 46e09a7af769-7cc66a0eb39mr7311673a34.20.1766438055630; Mon, 22 Dec 2025 13:14:15 -0800 (PST) X-BeenThere: bitcoindev@googlegroups.com; h="AWVwgWYWEYAk5bVLY1wfFC5lmT8OmXIR3SR2X/MGlwoYKdBjlA==" Received: by 2002:a05:6870:a11d:b0:3f9:f658:fe8 with SMTP id 586e51a60fabf-3f9f6582e06ls2802674fac.1.-pod-prod-00-us; Mon, 22 Dec 2025 13:14:09 -0800 (PST) X-Received: by 2002:a05:6808:2186:b0:44f:6df8:6a2f with SMTP id 5614622812f47-457b224549emr4635765b6e.23.1766438049681; Mon, 22 Dec 2025 13:14:09 -0800 (PST) Received: by 2002:a05:690c:688c:b0:786:8d90:70d8 with SMTP id 00721157ae682-78fb3c672f8ms7b3; Mon, 22 Dec 2025 12:47:11 -0800 (PST) X-Received: by 2002:a05:690e:13c4:b0:63f:ae23:b5e6 with SMTP id 956f58d0204a3-6466329d2b9mr14024454d50.26.1766436430948; Mon, 22 Dec 2025 12:47:10 -0800 (PST) Date: Mon, 22 Dec 2025 12:47:10 -0800 (PST) From: Sebastian Falbesoner To: Bitcoin Development Mailing List Message-Id: <59b1879d-b43d-41ac-9b3e-3e65cf31d4e5n@googlegroups.com> In-Reply-To: References: Subject: Re: [bitcoindev] [BIP Proposal] Add sp() output descriptor format for BIP352 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_Part_567530_414836269.1766436430535" X-Original-Sender: sebastian.falbesoner@gmail.com Precedence: list Mailing-list: list bitcoindev@googlegroups.com; contact bitcoindev+owners@googlegroups.com List-ID: X-Google-Group-Id: 786775582512 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , X-Spam-Score: -0.5 (/) ------=_Part_567530_414836269.1766436430535 Content-Type: multipart/alternative; boundary="----=_Part_567531_1122006532.1766436430535" ------=_Part_567531_1122006532.1766436430535 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hi Craig, a few comments about the cost of label scanning, as this topic comes up repeatedly: > The problem with this approach is that scanning for each additional label > adds incrementally and non-trivially to the computational burden. I think this statement is a misconception or at best only half of the truth= , likely based on the assumption that all existing and future SP wallets woul= d implement scanning using the same method. > For each label, there is an EC point addition and comparison against all > taproot outputs for an eligible transaction. Iterating through labels and calculating taproot outputs to match for is=20 only one way to implement scanning. Another one, as laid out in BIP-352 [1], is= =20 to do it backwards: for each taproot output, subtract the output candidate and check if the result is in the label cache. One advantage of this approach i= s that its scanning cost is independent of the number of labels to scan for,= =20 as the lookup time in the cache is constant and efficient if a proper data structure is used. To prove that point, I've extended the scanning benchmark of the libsecp SP module PR #1765 [2] with an _actual_ label cache using a third-party hash table implementation [3]: https://github.com/theStack/secp256k1/commit/f9f41adcedaca98aa4f3f65e2782e2= 5b2124bf85 The scanning time is measured with three different label cache sizes: no entries (i.e. empty lookup function stub, no hash-map involved), one entry ("tiny"), and one million entries ("huge"). Running the benchmark for=20 scanning a transaction with 10 taproot outputs leads to the following output: $ ./build/bin/bench sp_scan_with_labels Benchmark , Min(us) , Avg(us) , = =20 Max(us) sp_scan_with_label_cache_empty_L=3D0 , 61.3 , 61.4 ,= =20 61.4 sp_scan_with_label_cache_tiny_L=3D1 , 61.6 , 61.6 ,= =20 61.7 sp_scan_with_label_cache_huge_L=3D1000000 , 61.6 , 61.7 ,= =20 61.7 This shows that the cache lookup cost is negligible even for hundreds of thousands of labels, compared to other much more costly EC operations in th= e scanning function. With only a handful of labels to scan for, the "iterate over labels"=20 approach is faster (certainly if only scanning for the change label), but at some cross-over point the BIP-style scanning with label-cache lookup performs better [4], and at that point the scanning performance doesn't get worse anymore, i.e. each additional label is for free.=20 Given that this alternative scanning approach exists, I don't think it is appropriate to say that label scanning doesn't scale in general. It is my understanding that this BIP-style scanning might not work well for light clients, as they usually don't have the (full) transaction output data to start with, so it's not applicable for all types of wallets. Still, there might be full-node wallets in the future with special use-cases that can=20 deal with hundreds of thousands of labels without a noticeable decline in=20 scanning performance; if they choose the scanning approach as described in the BIP,= =20 and implement the label cache using an efficient data structure, there shouldn'= t be any problems. Hence, I'd be in favor of allowing label ranges in the SP descriptor format= . Even for use-cases with a smaller amount of labels, it seems to make sense= =20 to shorten the descriptor string in most cases. I can't think of any good=20 reasons for introducing gaps in the m values for label creation. I'm still curious to hear some more concrete use-cases for labels in genera= l and especially large amount of labels. (Admittedly, if we were absolutely certain that there will never be any use for that, there would indeed not= =20 much point in allowing lots of labels, but we have no way of knowing, and restricting potential use-cases doesn't seem the right approach to me). Cheers, Sebastian [1]=20 https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki#user-content= -Scanning,=20 see "check for labels" ff. [2] https://github.com/bitcoin-core/secp256k1/pull/1765 [3] using the header-only libraries khash.h (for the hash-map) and=20 rapidhash.h (as hash function), see https://github.com/attractivechaos/klib/blob/master/khash.h and https://github.com/Nicoshev/rapidhash/blob/master/rapidhash.h [4] in theory, whenever the number of labels L is larger than twice the=20 number of taproot outputs N (i.e. L > 2*N), BIP-style scanning should be faster;= =20 see https://gist.github.com/theStack/25c77747838610931e8bbeb9d76faf78?permalink= _comment_id=3D5897811#gistcomment-5897811 for benchmarks over a L/N matrix On Sunday, December 14, 2025 at 9:33:03=E2=80=AFPM UTC+1 Oghenovo Usiwoma w= rote: > Hi Craig, > > > > IIUC, this creates a descriptor with a variable length. What if we=20 > encoded multiple labels in one number? For example, labels 1, 5, 10 are= =20 > encoded into a 64-bit number by setting the corresponding bit positions t= o=20 > '1' so that the final number is '1058'. Using one number to encode the=20 > labels is very appealing to me. > > > Descriptors are generally of variable length, so I'm not sure why this= =20 > is so appealing. Not only does this limit the range from 1 to 63, it has= =20 > the added disadvantage of making this part of the descriptor unreadable t= o=20 > most humans. > > I was thinking about a descriptor with thousands of labels and I thought = I=20 > could encode a large list of numbers into 64 bit number, but that=E2=80= =99s=20 > impossible. > > Consider this idea, if we strictly increment the label by one, then just= =20 > writing the max label, '10', in this example should be sufficient to tell= =20 > the wallet to check for labels 1.. 10. The previous example used "1, 5, 1= 0"=20 > as labels, but I'm not sure why we would we use label '1' and skip to '5'= ,=20 > so writing just the max label should work? > > > I'm still not in support of using new key formats for the descriptor, but= =20 > I'll see if they receive popular support. > > Novo. > > On Fri, 12 Dec 2025, 10:18=E2=80=AFam Craig Raw, wrot= e: > >> Hi Novo, >> >> Responses inline: >> >> > However, without the birthday, the descriptor will still be able to=20 >> describe its outputs. The birthday can be collected through some other= =20 >> means, as we do with other descriptors today. >> >> Indeed, that is why it is an optional argument. Again however, other=20 >> descriptors do not have to bear the very significant computational overh= ead=20 >> that sp() descriptors do. For many deployment contexts, this will=20 >> effectively make the birthday a requirement to retrieve all silent payme= nt=20 >> outputs in a wallet within a usable time frame. Other descriptors do not= =20 >> share such a stark usability challenge. >> >> > With existing key formats, users and wallets will be able use their=20 >> existing master key to generate silent payment outputs using a descripto= r=20 >> like: sp(/352h/1h/0h/1h/0,/352h/1h/0h/0h/0). >> >> You are requiring the user to specify their master xprv in an output=20 >> descriptor, even for a watch-only wallet. This is a non-starter. Today,= =20 >> output descriptors are often stored in clear text alongside a hardware= =20 >> wallet or similar as privacy-sensitive but not directly security-sensiti= ve=20 >> information. >> >> > > The advantages of Bech32m encoding, including strong error detection= =20 >> and unambiguous characters >> > I'm not sure these are strong enough to warrant new key formats. >> >> To the contrary, the use of output descriptors today means they are ofte= n=20 >> written down (sometimes into durable media). In this context, the=20 >> advantages of strong error detection and unambiguous characters are=20 >> significant. >> >> > > Safety from accidentally mixing different unrelated scan and spend= =20 >> keys >> > I'm not sure what the chance of this happening is.... If this is done= =20 >> properly, then the keys should not be mixed up. >> >> It might also be done intentionally, with unexpected results. Regardless= =20 >> of the cause, having one key expression discourages this. >> >> > We should use the descriptor prefix to indicate the silent payments=20 >> version instead of the keys. >> >> Indeed, silent payments version 1 may use a different script expression.= =20 >> The versioning here is still useful though. >> >> > Things can be even simpler without the new key format. >> >> This is an unsubstantiated statement, suggesting that two key expression= s=20 >> are somehow simpler than one. Again, it is simpler for wallet developers= =20 >> and users to adapt to formats that are similar to those they are already= =20 >> familiar with - and they are very familiar with xpubs. >> >> > IIUC, this creates a descriptor with a variable length. What if we=20 >> encoded multiple labels in one number? For example, labels 1, 5, 10 are= =20 >> encoded into a 64-bit number by setting the corresponding bit positions = to=20 >> '1' so that the final number is '1058'. Using one number to encode the= =20 >> labels is very appealing to me. >> >> Descriptors are generally of variable length, so I'm not sure why this i= s=20 >> so appealing. Not only does this limit the range from 1 to 63, it has th= e=20 >> added disadvantage of making this part of the descriptor unreadable to m= ost=20 >> humans. >> >> Best regards, >> Craig >> >> On Fri, Dec 12, 2025 at 9:22=E2=80=AFAM Oghenovo Usiwoma =20 >> wrote: >> >>> Hi Craig, >>> >>> I see how adding the birthday to the descriptor string could be=20 >>> beneficial for anyone trying to use a third-party scanning server; they= =20 >>> will only have to submit the descriptor string, and the server will=20 >>> automatically determine what height to start scanning from. However,=20 >>> without the birthday, the descriptor will still be able to describe its= =20 >>> outputs. The birthday can be collected through some other means, as we = do=20 >>> with other descriptors today. >>> >>> I'm opposed to using new key formats because I do not think we have=20 >>> enough justification to do so. With existing key formats, users and wal= lets=20 >>> will be able use their existing master key to generate silent payment= =20 >>> outputs using a descriptor like:=20 >>> sp(/352h/1h/0h/1h/0,/352h/1h/0h/0h/0). >>> >>> > A self-describing format which makes the use and sensitivity of the= =20 >>> key material immediately obvious >>> > The advantages of Bech32m encoding, including strong error detection= =20 >>> and unambiguous characters >>> I'm not sure these are strong enough to warrant new key formats. >>> >>> > Safety from accidentally mixing different unrelated scan and spend ke= ys >>> I'm not sure what the chance of this happening is. We already have=20 >>> descriptors with multiple keys having complex relationships. Compared t= o=20 >>> those, the "sp()" is simple. Users are supposed to back up the entire= =20 >>> descriptor string. If this is done properly, then the keys should not b= e=20 >>> mixed up. >>> >>> > Versioning to indicate silent payments version 0 >>> We should use the descriptor prefix to indicate the silent payments=20 >>> version instead of the keys. >>> >>> > A similar format to an xpub, the display of which is a common user=20 >>> interface element in many wallets, which makes things simpler for walle= t=20 >>> developers and users alike >>> Things can be even simpler without the new key format. >>> >>> From your original email: >>> > Finally, zero or more positive integers may be specified as further= =20 >>> arguments to scan for additional BIP352 labels. >>> IIUC, this creates a descriptor with a variable length. What if we=20 >>> encoded multiple labels in one number? For example, labels 1, 5, 10 are= =20 >>> encoded into a 64-bit number by setting the corresponding bit positions= to=20 >>> '1' so that the final number is '1058'. Using one number to encode the= =20 >>> labels is very appealing to me. >>> >>> Kind regards, >>> Novo >>> >>> On Thu, Dec 4, 2025 at 12:02=E2=80=AFPM Craig Raw w= rote: >>> >>>> Hi Novo, >>>> >>>> Responses inline: >>>> >>>> > I'm not sure adding a block height does much to reduce scanning=20 >>>> burden. We can already scan from the taproot activation height and it = won't=20 >>>> matter much anyway, because the chain will get longer and this only he= lps=20 >>>> temporarily. >>>> >>>> I'm not sure I follow here. Since we need to retrieve and compute=20 >>>> possible matching outputs for all eligible public keys in the chain, h= aving=20 >>>> a block height later than the Taproot activation date can make a=20 >>>> significant difference, and will make a greater difference in future a= s the=20 >>>> chain grows. >>>> >>>> > Is there any reason to add the birthday to the descriptor? Other=20 >>>> descriptors do not do this. >>>> >>>> The difference between this and other descriptors is that it cannot=20 >>>> describe outputs without reference to the blockchain. This, combined w= ith=20 >>>> the significant computational burden which other descriptors do not ha= ve to=20 >>>> bear, is reason enough I think to include it here as an optional argum= ent. >>>> >>>> > For example, we can set the maximum number of labels in the bip;=20 >>>> wallets will only have to scan for this max number of labels during=20 >>>> recovery and if a wallet goes beyond this maximum number, they have go= ne=20 >>>> beyond the bip and are now responsible for ensuring full recovery of f= unds.=20 >>>> >>>> The problem with this approach is that scanning for each additional=20 >>>> label adds incrementally and non-trivially to the computational burden= . For=20 >>>> each label, there is an EC point addition and comparison against all= =20 >>>> taproot outputs for an eligible transaction. Some benchmark numbers=20 >>>> indicating the relative cost of each additional label are in [1],=20 >>>> demonstrating that scanning for 100k labels is cost-prohibitive. As an= =20 >>>> aside, I will add that labels have a limited use case, and in most cas= es a=20 >>>> new BIP44 account is a better choice for additional silent payment=20 >>>> addresses based on the same seed. >>>> >>>> > Given the above points, I argue that we don't need to introduce new= =20 >>>> scan and spend key formats, and we can use "sp(scankey,spendkey)". >>>> >>>> While not strictly necessary, using spscan and spspend key=20 >>>> expressions make for a much better user experience and reduce the chan= ce=20 >>>> for user error. With this encoding we get: >>>> >>>> 1. A self-describing format which makes the use and sensitivity of= =20 >>>> the key material immediately obvious >>>> 2. The advantages of Bech32m encoding, including strong error=20 >>>> detection and unambiguous characters >>>> 3. Safety from accidentally mixing different unrelated scan and=20 >>>> spend keys >>>> 4. Versioning to indicate silent payments version 0 >>>> 5. A similar format to an xpub, the display of which is a common=20 >>>> user interface element in many wallets which makes things simpler f= or=20 >>>> wallet developers and users alike >>>> >>>> --Craig >>>> >>>> [1]: https://delvingbitcoin.org/t/bip352-private-key-formats/2080/11 >>>> >>>> On Thu, Dec 4, 2025 at 11:39=E2=80=AFAM Oghenovo Usiwoma =20 >>>> wrote: >>>> >>>>> Hi Craig, thank you for taking this up. I have the following comments= ,=20 >>>>> based on a light inspection of your original email. >>>>> >>>>> > In order to reduce the scanning burden, a block height may be=20 >>>>> optionally specified in the sp() expression as a second argument for = a=20 >>>>> wallet birthday. >>>>> >>>>> I'm not sure adding a block height does much to reduce scanning=20 >>>>> burden. We can already scan from the taproot activation height and it= won't=20 >>>>> matter much anyway, because the chain will get longer and this only h= elps=20 >>>>> temporarily. >>>>> >>>>> Users can also specify a "wallet birthday" in their wallets which can= =20 >>>>> be used for scanning. Is there any reason to add the birthday to the= =20 >>>>> descriptor? Other descriptors do not do this. >>>>> >>>>> > Finally, zero or more positive integers may be specified as further= =20 >>>>> arguments to scan for additional BIP352 labels. The change label (m = =3D 0) is=20 >>>>> implicitly included. >>>>> >>>>> In=20 >>>>> https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki#backup= -and-recovery=20 >>>>> , a strategy to recover funds from labels is specified. We can attemp= t to=20 >>>>> make this stronger and avoid the need to also include an integer for= =20 >>>>> labels. For example, we can set the maximum number of labels in the b= ip;=20 >>>>> wallets will only have to scan for this max number of labels during= =20 >>>>> recovery and if a wallet goes beyond this maximum number, they have g= one=20 >>>>> beyond the bip and are now responsible for ensuring full recovery of = funds.=20 >>>>> >>>>> > In summary a new top level script expression sp() is defined, which= =20 >>>>> takes as it's first argument one of two new key expressions: >>>>> - spscan1q... which encodes the scan private key and the spend public= =20 >>>>> key >>>>> - spspend1q... which encodes the scan private key and the spend=20 >>>>> private key >>>>> >>>>> Given the above points, I argue that we don't need to introduce new= =20 >>>>> scan and spend key formats, and we can use "sp(scankey,spendkey)". >>>>> >>>>> I'm happy to hear any counter arguments you have. >>>>> >>>>> Novo >>>>> >>>>> On Thu, 4 Dec 2025, 12:40=E2=80=AFpm Craig Raw, w= rote: >>>>> >>>>>> Hi all, >>>>>> >>>>>> There is a practical need for a silent payments output descriptor=20 >>>>>> format in order to enable wallet interoperability and backup/recover= y.=20 >>>>>> There has been some prior discussion on this topic [1][2] which this= BIP=20 >>>>>> proposal builds on: >>>>>> >>>>>> https://github.com/bitcoin/bips/pull/2047 >>>>>> >>>>>> In summary a new top level script expression sp() is defined, which= =20 >>>>>> takes as it's first argument one of two new key expressions: >>>>>> >>>>>> - spscan1q... which encodes the scan private key and the spend=20 >>>>>> public key >>>>>> - spspend1q... which encodes the scan private key and the spend= =20 >>>>>> private key >>>>>> >>>>>> The outputs may then be generated by combining this key material wit= h=20 >>>>>> the sender input public keys.=20 >>>>>> >>>>>> In order to reduce the scanning burden, a block height may be=20 >>>>>> optionally specified in the sp() expression as a second argument for= a=20 >>>>>> wallet birthday. Finally, zero or more positive integers may be spec= ified=20 >>>>>> as further arguments to scan for additional BIP352 labels. The chang= e label=20 >>>>>> (m =3D 0) is implicitly included. >>>>>> >>>>>> Examples: >>>>>> sp(spscan1q...) >>>>>> sp([deadbeef/352'/0'/0']spscan1q...,900000) >>>>>> sp(spspend1q...,842579,1,2,3) >>>>>> sp([deadbeef/352'/0'/0']spscan1q...,900000,1,5,10) >>>>>> >>>>>> --Craig >>>>>> >>>>>> [1]:=20 >>>>>> https://btctranscripts.com/bitcoin-core-dev-tech/2024-04/silent-paym= ent-descriptors >>>>>> [2]: https://delvingbitcoin.org/t/bip352-private-key-formats/2080 >>>>>> >>>>>> --=20 >>>>>> You received this message because you are subscribed to the Google= =20 >>>>>> Groups "Bitcoin Development Mailing List" group. >>>>>> To unsubscribe from this group and stop receiving emails from it,=20 >>>>>> send an email to bitcoindev+...@googlegroups.com. >>>>>> To view this discussion visit=20 >>>>>> https://groups.google.com/d/msgid/bitcoindev/CAPR5oBNCd65XaipOF%3DeX= W7PT%2BJRVC4m6ey%2BX42aQsKa1YzA-Xw%40mail.gmail.com=20 >>>>>> >>>>>> . >>>>>> >>>>>> --=20 You received this message because you are subscribed to the Google Groups "= Bitcoin Development Mailing List" group. To unsubscribe from this group and stop receiving emails from it, send an e= mail to bitcoindev+unsubscribe@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/bitcoindev/= 59b1879d-b43d-41ac-9b3e-3e65cf31d4e5n%40googlegroups.com. ------=_Part_567531_1122006532.1766436430535 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hi Craig,

a few comments about the cost of label scanning, as th= is topic comes up
repeatedly:

> The problem with this ap= proach is that scanning for each additional label
> adds incrementa= lly and non-trivially to the computational burden.

I think this = statement is a misconception or at best only half of the truth,
likely= based on the assumption that all existing and future SP wallets would
implement scanning using the same method.

> For each label, = there is an EC point addition and comparison against all
> taproot = outputs for an eligible transaction.

Iterating through labels an= d calculating taproot outputs to match for is only
one way to implemen= t scanning. Another one, as laid out in BIP-352 [1], is to
do it backw= ards: for each taproot output, subtract the output candidate and
check= if the result is in the label cache. One advantage of this approach is
that its scanning cost is independent of the number of labels to scan for= , as
the lookup time in the cache is constant and efficient if a prope= r data
structure is used.

To prove that point, I've extende= d the scanning benchmark of the libsecp SP
module PR #1765 [2] with an= _actual_ label cache using a third-party hash
table implementation [3= ]:
https://github.com/theStack/secp256k1/commit/f9f41adcedaca98aa4f3f6= 5e2782e25b2124bf85

The scanning time is measured with three diff= erent label cache sizes: no
entries (i.e. empty lookup function stub, = no hash-map involved), one entry
("tiny"), and one million entries ("h= uge"). Running the benchmark for scanning
a transaction with 10 taproo= t outputs leads to the following output:

$ ./build/bin/bench sp_= scan_with_labels
Benchmark =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 , =C2=A0 =C2= =A0Min(us) =C2=A0 =C2=A0, =C2=A0 =C2=A0Avg(us) =C2=A0 =C2=A0, =C2=A0 =C2=A0= Max(us)

sp_scan_with_label_cache_empty_L=3D0 =C2=A0 =C2=A0 =C2= =A0, =C2=A0 =C2=A061.3 =C2=A0 =C2=A0 =C2=A0 , =C2=A0 =C2=A061.4 =C2=A0 =C2= =A0 =C2=A0 , =C2=A0 =C2=A061.4
sp_scan_with_label_cache_tiny_L=3D1 =C2= =A0 =C2=A0 =C2=A0 , =C2=A0 =C2=A061.6 =C2=A0 =C2=A0 =C2=A0 , =C2=A0 =C2=A06= 1.6 =C2=A0 =C2=A0 =C2=A0 , =C2=A0 =C2=A061.7
sp_scan_with_label_cache_= huge_L=3D1000000 , =C2=A0 =C2=A061.6 =C2=A0 =C2=A0 =C2=A0 , =C2=A0 =C2=A061= .7 =C2=A0 =C2=A0 =C2=A0 , =C2=A0 =C2=A061.7

This shows that the = cache lookup cost is negligible even for hundreds of
thousands of labe= ls, compared to other much more costly EC operations in the
scanning f= unction.

With only a handful of labels to scan for, the "iterate= over labels" approach
is faster (certainly if only scanning for the c= hange label), but at some
cross-over point the BIP-style scanning with= label-cache lookup performs
better [4], and at that point the scannin= g performance doesn't get worse
anymore, i.e. each additional label is= for free.

Given that this alternative scanning approach exists= , I don't think it is
appropriate to say that label scanning doesn't s= cale in general. It is my
understanding that this BIP-style scanning m= ight not work well for light
clients, as they usually don't have the (= full) transaction output data to
start with, so it's not applicable fo= r all types of wallets. Still, there
might be full-node wallets in the= future with special use-cases that can deal
with hundreds of thousand= s of labels without a noticeable decline in scanning
performance; if t= hey choose the scanning approach as described in the BIP, and
implemen= t the label cache using an efficient data structure, there shouldn't
b= e any problems.

Hence, I'd be in favor of allowing label ranges = in the SP descriptor format.
Even for use-cases with a smaller amount = of labels, it seems to make sense to
shorten the descriptor string in = most cases. I can't think of any good reasons
for introducing gaps in = the m values for label creation.

I'm still curious to hear some = more concrete use-cases for labels in general
and especially large amo= unt of labels. (Admittedly, if we were absolutely
certain that there w= ill never be any use for that, there would indeed not much
point in al= lowing lots of labels, but we have no way of knowing, and
restricting = potential use-cases doesn't seem the right approach to me).

Chee= rs,
Sebastian

[1] https://github.com/bitcoin/bips/blob/mast= er/bip-0352.mediawiki#user-content-Scanning, see "check for labels" ff.
[2] https://github.com/bitcoin-core/secp256k1/pull/1765
[3] using th= e header-only libraries khash.h (for the hash-map) and rapidhash.h
(as= hash function), see
https://github.com/attractivechaos/klib/blob/mast= er/khash.h and
https://github.com/Nicoshev/rapidhash/blob/master/rapid= hash.h
[4] in theory, whenever the number of labels L is larger than t= wice the number
of taproot outputs N (i.e. L > 2*N), BIP-style scan= ning should be faster; see
https://gist.github.com/theStack/25c7774783= 8610931e8bbeb9d76faf78?permalink_comment_id=3D5897811#gistcomment-5897811for benchmarks over a L/N matrix

=
On Sunday, December 14, 2025 at 9:33= :03=E2=80=AFPM UTC+1 Oghenovo Usiwoma wrote:
Hi Crai= g,

> > IIUC,= this creates a descriptor with a variable length. What if we encoded multi= ple labels in one number? For example, labels 1, 5, 10 are encoded into a 6= 4-bit number by setting the corresponding bit positions to '1' so t= hat the final number is '1058'. Using one number to encode the labe= ls is very appealing to me.

&g= t; Descriptors are generally of variable length, so I'm not sure why th= is is so appealing. Not only does this limit the range from 1 to 63, it has= the added disadvantage of making this part of the descriptor unreadable to= most humans.

I was thinking about a descriptor with thousands of labels an= d I thought I could encode a large list of numbers into 64 bit number, but = that=E2=80=99s impossible.

Consider this idea, if we strictly increment the label by one, then just= writing the max label, '10', in this example should be sufficient = to tell the wallet to check for labels 1.. 10. The previous example used &q= uot;1, 5, 10" as labels, but I'm not sure why we would we use labe= l '1' and skip to '5', so writing just the max label should= work?


I'm still not in support of using new key formats for the de= scriptor, but I'll see if they receive popular support.

Novo.
On Fri, 12 Dec 2025, 10:18=E2=80=AFam Craig Raw, <crai...@gmail.com> wrote:
Hi Novo,

Respon= ses inline:

> However, without the birthday, th= e descriptor will still be able to describe its outputs. The birthday can b= e collected through some other means, as we do with other descriptors today= .

Indeed, that is why it is an optional argument. = Again however, other descriptors do not have to bear the very significant c= omputational overhead that sp() descriptors do. For many deployment context= s, this will effectively make the birthday a requirement to retrieve all si= lent payment outputs in a wallet within a usable time frame. Other descript= ors do not share such a stark usability challenge.

> With existing key formats, users and wallets will be able use their e= xisting master key to generate silent payment outputs using a descriptor li= ke: sp(<master_key>/352h/1h/0h/1h/0,<master_key>/352h/1h/0h/0h/= 0).

You are requiring the user to specify their ma= ster xprv in an output descriptor, even for a watch-only wallet.=C2=A0This = is a non-starter. Today, output descriptors are often stored in clear text = alongside a hardware wallet or similar as privacy-sensitive but not directl= y security-sensitive information.

> > The ad= vantages of Bech32m encoding, including strong error detection and unambigu= ous characters
> I'm not sure these are strong enough to w= arrant new key formats.

To the contrary, the use o= f output descriptors today means they are often written down (sometimes int= o durable media). In this context, the advantages of strong error detection= and unambiguous characters are significant.

> = >=C2=A0Safety from accidentally mixing different unrelated scan and spen= d keys
> I'm not sure what the chance of this happening is= .... If this is done properly, then the keys should not be mixed up.
<= div>
It might also be done intentionally, with unexpected res= ults. Regardless of the cause, having one key expression discourages this.<= /div>

> We should use the descriptor prefix to indica= te the silent payments version instead of the keys.

Indeed, silent payments version 1 may use a different script expression. = The versioning here is still useful though.

> T= hings can be even simpler without the new key format.

<= div>This is an unsubstantiated statement, suggesting that two key expressio= ns are somehow simpler than one. Again, it is simpler for wallet developers= and users to adapt to formats that are similar to those they are already f= amiliar with - and they are very familiar with xpubs.

<= div>> IIUC, this creates a descriptor with a variable length. What if we= encoded multiple labels in one number? For example, labels 1, 5, 10 are en= coded into a 64-bit number by setting the corresponding bit positions to &#= 39;1' so that the final number is '1058'. Using one number to e= ncode the labels is very appealing to me.

Descript= ors are generally of variable length, so I'm not sure why this is so ap= pealing. Not only does this limit the range from 1 to 63, it has the added = disadvantage=C2=A0of making this part of the descriptor unreadable to most = humans.

Best regards,
Craig
<= br>
On Fri,= Dec 12, 2025 at 9:22=E2=80=AFAM Oghenovo Usiwoma <eun...@gmail.com> wrote:
<= blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-l= eft:1px solid rgb(204,204,204);padding-left:1ex">
Hi Craig,=

I see how adding the birthday to the descriptor string could be ben= eficial for anyone trying to use a third-party scanning server; they will o= nly have to submit the descriptor string, and the server will automatically= determine what height to start scanning from. However, without the birthda= y, the descriptor will still be able to describe its outputs. The birthday = can be collected through some other means, as we do with other descriptors = today.

I'm opposed to using new key formats because I do not thi= nk we have enough justification to do so. With existing key formats, users = and wallets will be able use their existing master key to generate silent p= ayment outputs using a descriptor like: sp(<master_key>/352h/1h/0h/1h= /0,<master_key>/352h/1h/0h/0h/0).

> A self-describing forma= t which makes the use and sensitivity of the key material immediately obvio= us
> The advantages of Bech32m encoding, including strong error detec= tion and unambiguous characters
I'm not sure these are strong enough= to warrant new key formats.

>=C2=A0Safety from accidentally mixi= ng different unrelated scan and spend keys
I'm not sure what the cha= nce of this happening is. We already have descriptors with multiple=C2=A0ke= ys having complex relationships. Compared to those, the "sp()" is= simple. Users are supposed to back up the entire descriptor string. If thi= s is done properly, then the keys should not be mixed up.

>=C2=A0= Versioning to indicate silent payments version 0
We should use the descr= iptor prefix to indicate the silent payments version instead of the keys.
>=C2=A0A similar format to an xpub, the display of which is a comm= on user interface element in many wallets, which makes things simpler for w= allet developers and users alike
Things can be even simpler without the = new key format.

From your original email:
> Finally, zero or m= ore positive integers may be specified as further arguments to scan for add= itional BIP352 labels.
IIUC, this creates a descriptor with a variable l= ength. What if we encoded multiple labels in one number? For example, label= s 1, 5, 10 are encoded into a 64-bit number by setting the corresponding bi= t positions to '1' so that the final number is '1058'. Usin= g one number to encode the labels is very appealing to me.

Kind rega= rds,
Novo

On Thu, Dec 4, 2025 at 12:02=E2=80=AFPM Craig Raw <crai...@gmail.com> wrot= e:
Hi Novo,

Responses inline:

= > I'm not sure adding a block height does much to reduce scanning bu= rden. We can already scan from the taproot activation height and it won'= ;t matter much anyway, because the chain will get longer and this only help= s temporarily.

I'm not sure I follow here. Sin= ce we need to retrieve and compute possible matching outputs for all eligib= le=C2=A0public keys in the chain, having a block height later than the Tapr= oot activation date can make a significant difference, and will make a grea= ter difference in future as the chain grows.

> = Is there any reason to add the birthday to the descriptor? Other descriptor= s do not do this.

The difference between this and = other descriptors is that it cannot describe outputs without reference to t= he blockchain. This, combined with the significant=C2=A0computational burde= n=C2=A0which other descriptors do not have to bear, is reason enough I thin= k to include it here as an optional argument.

>= For example, we can set the maximum number of labels in the bip; wallets w= ill only have to scan for this max number of labels during recovery and if = a wallet goes beyond this maximum number, they have gone beyond the bip and= are now responsible for ensuring full recovery of funds.=C2=A0

The problem with t= his approach is that scanning for each additional label adds incrementally = and non-trivially to the computational burden. For each label, there is an = EC point addition and comparison against all taproot outputs for an eligibl= e transaction. Some benchmark numbers indicating=C2=A0the relative cost of = each additional label are in [1], demonstrating that scanning for 100k labe= ls is cost-prohibitive. As an aside, I will add that labels have a limited = use case, and in most cases a new BIP44 account is a better choice for addi= tional silent payment addresses based on the same seed.

>=C2=A0Given the above points, I arg= ue that we don't need to introduce new scan and spend key formats, and = we can use "sp(scankey,spendkey)".
=
While not strictly necessary, using spscan and spspend=C2=A0= key expressions=C2=A0make for a much better user experience and reduce the = chance for user error. With this encoding we get:
  1. A self-= describing format which makes the use and sensitivity of the key material i= mmediately obvious
  2. The advantages of Bech32m encoding, including st= rong error detection and unambiguous characters
  3. Safety from acciden= tally mixing different unrelated scan and spend keys
  4. Versioning to = indicate silent payments version 0
  5. A similar format to an xpub, the= display of which is a common user interface element in many wallets which = makes things simpler for wallet developers and users alike
<= div>--Craig



In=C2=A0https://github.com/= bitcoin/bips/blob/master/bip-0352.mediawiki#backup-and-recovery , a str= ategy to recover funds from labels is specified. We can attempt to make thi= s stronger and avoid the need to also include an integer for labels. For ex= ample, we can set the maximum number of labels in the bip; wallets will onl= y have to scan for this max number of labels during recovery and if a walle= t goes beyond this maximum number, they have gone beyond the bip and are no= w responsible for ensuring full recovery of funds.=C2=A0

> In summary a new top level script exp= ression sp() is defined, which takes as it's first argument one of two = new key expressions:
- spscan1q... which encodes the= scan private key and the spend public key
- spspend= 1q... which encodes the scan private key and the spend private key

Given the above points, I argue = that we don't need to introduce new scan and spend key formats, and we = can use "sp(scankey,spendkey)".

=
I'm happy to hear any counter arguments you have.

Novo

On Thu, 4 = Dec 2025, 12:40=E2=80=AFpm Craig Raw, <crai...@gmail.com> wrote:
Hi all,

There is a practical need for a silent payments output descriptor fo= rmat in order to enable wallet interoperability and backup/recovery. There = has been some prior discussion on this topic [1][2] which this BIP proposal= builds on:


In summary=C2=A0a new top level scri= pt expression sp() is defined, which takes as it's first argument one o= f two new key expressions:
  • sps= can1q... which encodes the scan private key and the spend public key
  • spspend1q... which encodes the=C2=A0scan priva= te=C2=A0key and the spend private key
The outputs may then be= generated by combining this key material with the sender input public keys= .=C2=A0

In order to reduce the scanning burd= en, a block height may be optionally specified in the sp() expression as a = second argument for a wallet birthday. Finally, zero or more positive integ= ers may be specified as further arguments to scan for additional BIP352 lab= els. The change label (m =3D 0) is implicitly included.

Examples:
sp(spscan1q...)
sp([deadbeef/352'/0= '/0']spscan1q...,900000)
sp(spspend1q...,842579,1,2,3)
sp([deadbeef/352'/0'/0']spscan1q...,900000,1,5,10)

--Craig

--
You received this message because you are subscribed to the Google Groups &= quot;Bitcoin Development Mailing List" group.
To unsubscribe from this group and stop receiving emails from it, send an e= mail to bi= tcoindev+...@googlegroups.com.
To view this discussion visit https://groups.= google.com/d/msgid/bitcoindev/CAPR5oBNCd65XaipOF%3DeXW7PT%2BJRVC4m6ey%2BX42= aQsKa1YzA-Xw%40mail.gmail.com.

--
You received this message because you are subscribed to the Google Groups &= quot;Bitcoin Development Mailing List" group.
To unsubscribe from this group and stop receiving emails from it, send an e= mail to bitcoind= ev+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/bitcoind= ev/59b1879d-b43d-41ac-9b3e-3e65cf31d4e5n%40googlegroups.com.
------=_Part_567531_1122006532.1766436430535-- ------=_Part_567530_414836269.1766436430535--