Silent Payments: sending #28201

pull josibake wants to merge 16 commits into bitcoin:master from josibake:implement-bip352-sending changing 62 files +14243 −274
  1. josibake commented at 4:37 pm on August 2, 2023: member

    This PR is part of integrating silent payments into Bitcoin Core. Status and tracking for the project is managed in #28536

    This PR depends on #28122 and is marked as a draft until it is merged. If interested in those commits, please review on #28122

    Sending

    Silent Payments logic

    The main focus of this PR is:

    • Applying the Taptweak to a taproot internal private key (this is a copy-paste of the code for applying the taptweak in the signing process)
    • Getting a private key from a given scriptPubKey
    • Creating silent payment outputs
    • Applying the created scriptPubKeys back to the vector of CRecipients

    The functions are then used together to create silent payment outputs during CreateTransactionInternal.

    Final steps

    The last commits ensure that:

    • Coin selection is silent payments aware and knows to exclude taproot script path spends and inputs with unknown witness when funding a transaction which pays to a silent payment address
    • The change output type is correctly chosen when paying to a silent payment address
    • Functional tests
  2. DrahtBot commented at 4:37 pm on August 2, 2023: contributor

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/28201.

    Reviews

    See the guideline for information on the review process. A summary of reviews will appear here.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #33036 (Update secp256k1 subtree to latest master by fanquake)
    • #32896 (wallet, rpc: add v3 transaction creation and wallet support by ishaanam)
    • #32763 (wallet: Replace CWalletTx::mapValue and vOrderForm with explicit class members by achow101)
    • #32724 (Musig2 tests by w0xlt)
    • #32579 (headerssync: Preempt unrealistic unit test behavior by hodlinator)
    • #32523 (wallet: Remove isminetypes by achow101)
    • #31974 (Drop testnet3 by Sjors)
    • #31244 (descriptors: MuSig2 by achow101)
    • #29675 (wallet: Be able to receive and spend inputs involving MuSig2 aggregate keys by achow101)
    • #28333 (wallet: Construct ScriptPubKeyMans with all data rather than loaded progressively by achow101)
    • #27260 (Enhanced error messages for invalid network prefix during address parsing. by portlandhodl)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

  3. DrahtBot added the label CI failed on Aug 2, 2023
  4. josibake renamed this:
    Silent Payments: implement sending
    Silent Payments: sending
    on Aug 3, 2023
  5. josibake force-pushed on Aug 3, 2023
  6. josibake force-pushed on Aug 3, 2023
  7. josibake force-pushed on Aug 3, 2023
  8. DrahtBot removed the label CI failed on Aug 3, 2023
  9. josibake commented at 9:50 am on August 3, 2023: member

    Maybe add a quick summary in the description with the main implementation differences relative to #24897. It seems a big one is that this doesn’t require an index!

    updated! I added the summary in #27827 and added links back to the parent PR in each of the child PRs.

  10. in src/wallet/spend.cpp:942 in 181e329a1d outdated
    899+    assert(tx_outpoints.size() > 0);
    900+    CKey scalar_ecdh_input = PrepareScalarECDHInput(input_private_keys, tx_outpoints);
    901+    std::vector<SilentPaymentRecipient> silent_payment_recipients = GroupSilentPaymentAddresses(silent_payment_destinations);
    902+    std::vector<CRecipient> outputs;
    903+    for (const auto& recipient : silent_payment_recipients) {
    904+        Sender sender{scalar_ecdh_input, recipient};
    


    josibake commented at 10:29 am on August 8, 2023:
    This does not need to be a struct, it can just be a function.
  11. in test/functional/wallet_silentpayments_sending.py:110 in e6f7458324 outdated
    86+            address=SILENT_PAYMENT_ADDRESS,
    87+            amount=21,
    88+        )
    89+        assert txid
    90+
    91+    def test_deterministic_send(self):
    


    BrandonOdiwuor commented at 5:32 pm on August 9, 2023:
    Incorporating logs within the test is crucial for offering transparent insight into the test’s progression, simplifying the identification of problems, and enhancing comprehension of the test’s overall behavior.
  12. in test/functional/wallet_silentpayments_sending.py:160 in e6f7458324 outdated
    122+                assert output["scriptPubKey"]["address"] == "bcrt1p5num3dvry0ffusg3s7v2j5fy025p95jtn6js65jlruwc69r9je2s6qfsj7"
    123+                break
    124+        else:
    125+            assert False
    126+
    127+    def test_address_reuse(self):
    


    BrandonOdiwuor commented at 5:34 pm on August 9, 2023:
    Also consider adding logs to this test as the ones above
  13. josibake force-pushed on Aug 30, 2023
  14. josibake force-pushed on Aug 30, 2023
  15. josibake force-pushed on Aug 31, 2023
  16. josibake force-pushed on Aug 31, 2023
  17. josibake force-pushed on Sep 8, 2023
  18. josibake force-pushed on Sep 11, 2023
  19. josibake force-pushed on Sep 11, 2023
  20. DrahtBot added the label CI failed on Sep 11, 2023
  21. josibake force-pushed on Sep 11, 2023
  22. josibake force-pushed on Sep 11, 2023
  23. josibake force-pushed on Sep 12, 2023
  24. josibake force-pushed on Sep 12, 2023
  25. josibake force-pushed on Sep 14, 2023
  26. DrahtBot removed the label CI failed on Sep 14, 2023
  27. DrahtBot added the label Needs rebase on Sep 19, 2023
  28. josibake force-pushed on Sep 21, 2023
  29. josibake force-pushed on Sep 21, 2023
  30. DrahtBot added the label CI failed on Sep 21, 2023
  31. DrahtBot removed the label Needs rebase on Sep 21, 2023
  32. DrahtBot removed the label CI failed on Sep 21, 2023
  33. josibake commented at 4:30 pm on September 26, 2023: member
    Note: send does not work, but sendall, sendtoaddress does
  34. josibake force-pushed on Oct 2, 2023
  35. josibake force-pushed on Oct 2, 2023
  36. DrahtBot added the label CI failed on Oct 2, 2023
  37. josibake force-pushed on Oct 3, 2023
  38. josibake force-pushed on Oct 3, 2023
  39. DrahtBot removed the label CI failed on Oct 4, 2023
  40. DrahtBot added the label Needs rebase on Oct 16, 2023
  41. josibake force-pushed on Jan 15, 2024
  42. DrahtBot removed the label Needs rebase on Jan 15, 2024
  43. DrahtBot commented at 9:36 pm on January 17, 2024: contributor

    🚧 At least one of the CI tasks failed. Make sure to run all tests locally, according to the documentation.

    Possibly this is due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    Leave a comment here, if you need help tracking down a confusing failure.

    Debug: https://github.com/bitcoin/bitcoin/runs/20505330863

  44. DrahtBot added the label CI failed on Jan 17, 2024
  45. josibake force-pushed on Jan 19, 2024
  46. DrahtBot removed the label CI failed on Jan 19, 2024
  47. willcl-ark added the label Wallet on Jan 24, 2024
  48. willcl-ark added the label Privacy on Jan 24, 2024
  49. DrahtBot added the label Needs rebase on Jan 26, 2024
  50. josibake force-pushed on Jan 26, 2024
  51. DrahtBot removed the label Needs rebase on Jan 26, 2024
  52. DrahtBot added the label CI failed on Feb 2, 2024
  53. DrahtBot removed the label CI failed on Feb 7, 2024
  54. DrahtBot added the label Needs rebase on Feb 20, 2024
  55. josibake force-pushed on Apr 22, 2024
  56. DrahtBot removed the label Needs rebase on Apr 22, 2024
  57. DrahtBot added the label CI failed on Apr 22, 2024
  58. DrahtBot commented at 9:52 pm on April 22, 2024: contributor

    🚧 At least one of the CI tasks failed. Make sure to run all tests locally, according to the documentation.

    Possibly this is due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    Leave a comment here, if you need help tracking down a confusing failure.

    Debug: https://github.com/bitcoin/bitcoin/runs/24114299414

  59. josibake force-pushed on Apr 27, 2024
  60. josibake force-pushed on May 5, 2024
  61. DrahtBot removed the label CI failed on May 5, 2024
  62. DrahtBot added the label Needs rebase on May 20, 2024
  63. achow101 referenced this in commit f0745d028e on Jun 27, 2024
  64. josibake force-pushed on Jul 15, 2024
  65. DrahtBot removed the label Needs rebase on Jul 15, 2024
  66. josibake force-pushed on Jul 23, 2024
  67. DrahtBot added the label CI failed on Jul 23, 2024
  68. DrahtBot commented at 10:45 am on July 23, 2024: contributor

    🚧 At least one of the CI tasks failed. Debug: https://github.com/bitcoin/bitcoin/runs/27794809832

    Make sure to run all tests locally, according to the documentation.

    The failure may happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

  69. DrahtBot added the label Needs rebase on Aug 2, 2024
  70. ryanofsky referenced this in commit b38fb19b7e on Aug 7, 2024
  71. josibake force-pushed on Apr 4, 2025
  72. DrahtBot removed the label Needs rebase on Apr 4, 2025
  73. josibake force-pushed on Apr 4, 2025
  74. josibake force-pushed on Apr 4, 2025
  75. DrahtBot removed the label CI failed on Apr 4, 2025
  76. josibake force-pushed on Apr 7, 2025
  77. DrahtBot added the label CI failed on Apr 27, 2025
  78. josibake force-pushed on May 13, 2025
  79. DrahtBot added the label Needs rebase on May 13, 2025
  80. josibake force-pushed on May 14, 2025
  81. DrahtBot removed the label Needs rebase on May 14, 2025
  82. DrahtBot removed the label CI failed on May 14, 2025
  83. DrahtBot added the label Needs rebase on May 16, 2025
  84. josibake force-pushed on Jul 10, 2025
  85. josibake force-pushed on Jul 11, 2025
  86. DrahtBot removed the label Needs rebase on Jul 11, 2025
  87. josibake force-pushed on Jul 16, 2025
  88. josibake force-pushed on Jul 16, 2025
  89. DrahtBot added the label CI failed on Jul 16, 2025
  90. DrahtBot commented at 9:18 am on July 16, 2025: contributor

    🚧 At least one of the CI tasks failed. Task lint: https://github.com/bitcoin/bitcoin/runs/46079826609 LLM reason (✨ experimental): The CI failure is due to a lint error related to subtree merging issues.

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

  91. josibake force-pushed on Jul 16, 2025
  92. josibake commented at 9:51 am on July 16, 2025: member
    CI failure is from the test each commit job not handling a subtree pull; ignoring for now and will look into a CI fix later.
  93. DrahtBot removed the label CI failed on Jul 16, 2025
  94. Squashed 'src/secp256k1/' changes from 4187a46649..9e85256bbe
    9e85256bbe docs: update README
    4b1fb2c186 ci: enable silentpayments module
    de508a78ac tests: add constant time tests
    45427dd4d7 tests: add BIP-352 test vectors
    6975614517 silentpayments: add benchmarks for scanning
    a9af9ebf35 silentpayments: add examples/silentpayments.c
    b06254b6c7 silentpayments: receiving
    3c9362dd6a silentpayments: recipient label support
    70e20b7145 silentpayments: sending
    cf44324b5e build: add skeleton for new silentpayments (BIP352) module
    ad60ef7ea7 Merge bitcoin-core/secp256k1#1689: ci: Convert `arm64` Cirrus tasks to GHA jobs
    c498779096 Merge bitcoin-core/secp256k1#1687: cmake: support the use of launchers in ctest -S scripts
    0dfe387dbe cmake: support the use of launchers in ctest -S scripts
    89096c234d Merge bitcoin-core/secp256k1#1692: cmake: configure libsecp256k1.pc during install
    7106dce6fd cmake: configure libsecp256k1.pc during install
    29e73f4ba5 Merge bitcoin-core/secp256k1#1685: cmake: Emulate Libtool's behavior on FreeBSD
    746e36b141 Merge bitcoin-core/secp256k1#1678: cmake: add a helper for linking into static libs
    a28c2ffa5c Merge bitcoin-core/secp256k1#1683: README: add link to musig example
    2a9d374735 Merge bitcoin-core/secp256k1#1690: ci: Bump GCC snapshot major version to 16
    add146e101 ci: Bump GCC snapshot major version to 16
    004f57fcd8 ci: Move Valgrind build for `arm64` from Cirrus to GHA
    5fafdfc30f ci: Move `gcc-snapshot` build for `arm64` from Cirrus to GHA
    e814b79a8b ci: Switch `arm64_debian` from QEMU to native `arm64` Docker image
    bcf77346b9 ci: Add `arm64` architecture to `docker_cache` job
    b77aae9226 ci: Rename Docker image tag to reflect architecture
    145ae3e28d cmake: add a helper for linking into static libs
    819210974b README: add link to musig example, generalize module enabling hint
    95db29b144 Merge bitcoin-core/secp256k1#1679: cmake: Use `PUBLIC_HEADER` target property in installation logic
    37dd422b5c cmake: Emulate Libtool's behavior on FreeBSD
    f24b838bed Merge bitcoin-core/secp256k1#1680: doc: Promote "Building with CMake" to standard procedure
    3f31ac43e0 doc: Promote "Building with CMake" to standard procedure
    6f67151ee2 cmake: Use `PUBLIC_HEADER` target property
    c32715b2a0 cmake, move-only: Move module option processing to `src/CMakeLists.txt`
    201b2b8f06 Merge bitcoin-core/secp256k1#1675: cmake: Bump minimum required CMake version to 3.22
    3af71987a8 cmake: Bump minimum required CMake version to 3.22
    92394476e9 Merge bitcoin-core/secp256k1#1673: Assert field magnitude at control-flow join
    3a4f448cb4 Assert field magnitude at control-flow join
    9fab425256 Merge bitcoin-core/secp256k1#1668: bench_ecmult: add benchmark for ecmult_const_xonly
    05445377f4 bench_ecmult: add benchmark for ecmult_const_xonly
    bb597b3d39 Merge bitcoin-core/secp256k1#1670: tests: update wycheproof files
    d73ed99479 tests: update wycheproof files
    
    git-subtree-dir: src/secp256k1
    git-subtree-split: 9e85256bbe527bf084222ee08dade9ea497d5c99
    46f5c2f1f3
  95. Merge commit '46f5c2f1f382922c19a070b78803fbd29cedd62b' into refresh-secp256k1 14224fd2f3
  96. crypto: add read-only method to KeyPair
    Add a method for passing a KeyPair object to secp256k1 functions expecting a secp256k1_keypair.
    This allows for passing a KeyPair directly to a secp256k1 function without needing to create a
    temporary secp256k1_keypair object.
    702eb96c46
  97. Add "sp" HRP 91d588d839
  98. Add V0SilentPaymentDestination address type d6070d3437
  99. common: add bip352.{h,cpp} secp256k1 module
    Wrap the silentpayments module from libsecp256k1. This is placed in
    common as it is intended to be used by:
    
      * RPCs: for parsing addresses
      * Wallet: for sending, receiving, spending silent payment outputs
      * Node: for creating silent payment indexes for light clients
    a0384589e4
  100. wallet: disable sending to silent payment address
    Have `IsValidDestination` return false for silent payment destinations
    and set an error string when decoding a silent payment address.
    
    This prevents anyone from sending to a silent payment address before
    sending is implemented in the wallet, but also allows the functions to
    be used in the unit testing famework.
    1765c1ff3d
  101. tests: add BIP352 test vectors as unit tests
    Use the test vectors to test sending and receiving. A few cases are not
    covered here, namely anything that requires testing specific to the
    wallet. For example:
    
    * Taproot script path spending is not tested, as that is better tested in
      a wallets coin selection / signing logic
    * Re-computing outputs during RBF is not tested, as that is better
      tested in a wallets RBF logic
    
    The unit tests are written in such a way that adding new test cases is
    as easy as updating the JSON file
    d820cf6c2d
  102. wallet: get serialized size for `V0SilentPayments`
    BIP352 v0 specifies that a silent payment output is a taproot output.
    Taproot scriptPubKeys are a fixed size, so when calculating the
    serialized size for a CRecipient with a V0SilentPayments destination,
    use WitnessV1Taproot for the serialized txout size.
    23182ba053
  103. wallet: add method for retreiving a private key
    Add a method for retreiving a private key for a given scriptPubKey.
    If the scriptPubKey is a taproot output, tweak the private key with the
    merkle root or hash of the public key, if applicable.
    7a253a80e7
  104. wallet: make coin selection silent payment aware
    Add a flag to the `CoinControl` object if silent payment destinations
    are provided. Before adding the flag, call a function which checks if:
    
    * The wallet has private keys
    * The wallet is unlocked
    
    Without both of the above being true, we cannot send to a silent payment
    address.
    
    During coin selection, if this flag is set, skip taproot inputs when
    script spend data is available. This is based on the assumption that if
    a user provides script spend data, they don't have access to the key
    path spend. As future improvement, we could instead check to see if we
    have access to the key path spend, and only exclude the output when we
    don't regardless of whether or not the user provides script spend data.
    
    Also skip UTXOs of type `WITNESS_UNKNOWN`, although it is very unlikely
    our wallet would ever try to spend a witness unknown output.
    e0404435ff
  105. wallet: add `IsInputForSharedSecretDerivation` function 51ad5fccb4
  106. wallet: add `CreateSilentPaymentOutputs` function
    `CreateSilentPaymentsOutputs` gets the correct private keys, adds them
    together, groups the silent payment destinations and then generates the
    taproot script pubkeys. These are then passed back to
    CreateTransactionInternal, which uses these scriptPubKeys to update
    vecSend before adding them to the transaction outputs.
    910b219900
  107. wallet: update TransactionChangeType
    If sending to a silent payment destination, the change type should be taproot
    3e7812364f
  108. wallet: enable sending to silent payment address
    Treat silent payment addresses as valid destination. Also disable using
    silent payment addresses with the `addr()` descriptor, as this
    descriptor expects an encoding of a scriptPubKey, whereas a silent
    payment address consists of instructions on how to generate a
    scriptPubKey for the recipient.
    
    Co-authored-by: Oghenovo Usiwoma <37949128+eunovo@users.noreply.github.com>
    d6fb7426c7
  109. tests: add sending functional tests 4225ebc655
  110. josibake force-pushed on Jul 17, 2025
  111. DrahtBot added the label Needs rebase on Jul 23, 2025
  112. DrahtBot commented at 10:47 am on July 23, 2025: contributor
    🐙 This pull request conflicts with the target branch and needs rebase.
  113. in src/wallet/spend.cpp:471 in e0404435ff outdated
    465@@ -450,6 +466,18 @@ CoinsResult AvailableCoins(const CWallet& wallet,
    466             type = Solver(script, script_solutions);
    467             is_from_p2sh = true;
    468         }
    469+        // Very unlikely we'd be spending a witness unknown output, but if we are trying to pay a
    470+        // silent payments v0 address, this can't be included
    471+        if (silent_payment && type == TxoutType::WITNESS_UNKNOWN) continue;
    


    Eunovo commented at 4:48 pm on July 23, 2025:
    https://github.com/bitcoin/bitcoin/pull/28201/commits/e0404435ff4d64b32b58774b6c909c66f1692a9f: TxoutType::PUBKEY which represents Pay2Pubkey outputs, is also not eligible to pay to silent payments outputs.

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2025-07-23 21:13 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me