[Draft/POC] Add secp256k1-based HPKE (Hybrid Public Key Encryption) For Payjoin v2 #32617

pull w0xlt wants to merge 1 commits into bitcoin:master from w0xlt:secp256k1_hpke changing 6 files +7460 −1
  1. w0xlt commented at 8:04 am on May 26, 2025: contributor

    This PR introduces an implementation of Hybrid Public Key Encryption (HPKE) using a secp256k1-based Diffie-Hellman KEM (per RFC 9180 and “secp256k1-based DHKEM for HPKE” specification). It provides the core cryptographic component needed to enable the Payjoin v2 protocol.

    This is an exploratory PR intended to kickstart discussion on adding Payjoin v2 support to Bitcoin Core – feedback and reviews are very welcome.

    Payjoin v2 makes use of a protocol called Oblivious HTTP (OHTTP) to strip client-identifying metadata from the request. This protocol use a binary-encoded HTTP message encapsulated through HPKE.

    The core implementation is contained in the new files src/dhkem_secp256k1.h and src/dhkem_secp256k1.cpp:

    • Full HPKE Modes: All four HPKE modes are supported – Base, PSK, Auth, and AuthPSK.
    • Secp256k1 DHKEM: Uses secp256k1 for Diffie-Hellman key exchange. The Encap() and Decap() functions perform the base mode KEM (ephemeral ECDH using the receiver’s public key), while AuthEncap() and AuthDecap() extend this to authenticated mode (including the sender’s static key in the shared secret derivation). Internally, the shared secret is derived as specified by HPKE using HKDF (SHA256) extraction and expansion.
    • Key Schedule & Nonce Derivation: After KEM, the implementation runs the HPKE key schedule to derive the encryption key, base nonce, and exporter secret. It follows RFC 9180 §7.1, hashing the info and psk_id contexts and deriving the AEAD key and nonce. Per-message nonces are computed by XOR-ing the base nonce with a message sequence number as specified in RFC 9180 §5.2.
    • AEAD Encryption (ChaCha20-Poly1305): The HPKE context uses ChaCha20-Poly1305 as the authenticated encryption scheme. The code provides Seal() and Open() functions to encrypt and decrypt data using the derived context key and a given nonce. It uses Bitcoin Core’s existing ChaCha20Poly1305 implementation.

    The test file validates all the functions mentioned above: Encapsulation/Decapsulation, Encryption/Decryption, Nonce and Key Schedule Logic. This uses the PDK (Payjoin Dev Kit) test vectors. The tests also show how to use the HPKE functions.

    This implementation only uses HKDF-SHA256 as Key Derivation Functions and ChaCha20-Poly1305 as AEAD, since these already exist in the Bitcoin Core codebase. It does not support other KDFs (such as HKDF-SHA384 and HKDF-SHA512) or other AEADs (such as AES-128-GCM and AES-256-GCM).

    To run the tests: build/bin/test_bitcoin --log_level=all --run_test=dhkem_secp256k1_tests

  2. w0xlt marked this as a draft on May 26, 2025
  3. DrahtBot commented at 8:04 am on May 26, 2025: 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/32617.

    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:

    • #28690 (build: Introduce internal kernel library by TheCharlatan)

    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.

  4. w0xlt force-pushed on May 26, 2025
  5. w0xlt force-pushed on May 26, 2025
  6. DrahtBot added the label CI failed on May 26, 2025
  7. DrahtBot commented at 9:34 am on May 26, 2025: contributor

    🚧 At least one of the CI tasks failed. Task lint: https://github.com/bitcoin/bitcoin/runs/42885844689 LLM reason (✨ experimental): The CI failure is due to a lint check raising an error over missing include guards in the header file.

    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.

  8. crypto: Add secp256k1-based DHKEM for HPKE (Hybrid Public Key Encryption) 588c67869f
  9. w0xlt force-pushed on May 26, 2025
  10. DrahtBot removed the label CI failed on May 26, 2025
  11. 1440000bytes commented at 11:42 am on May 26, 2025: none
    If rust-payjoin already works with bitcoin core wallet, why do we need to add anything in bitcoin core for payjoin?
  12. DanGould commented at 7:13 pm on May 26, 2025: none
    The main reason for the Bitcoin Core wallet to support payjoin directly is to reduce the number of necessary dependencies for those already using the core wallet. In particular rust-payjoin requires TLS (which is optional for the protocol) and rust implementations of cryptographic primatives that core could avoid with a bespoke implementation.
  13. theStack commented at 3:19 pm on June 3, 2025: contributor

    Fore more context to reviewers, could add a link to BIP 77 in the PR description, particularly to the cryptography part: https://github.com/bitcoin/bips/blob/master/bip-0077.md#secp256k1-hybrid-public-key-encryption

    Full HPKE Modes: All four HPKE modes are supported – Base, PSK, Auth, and AuthPSK.

    Do we need all of the four modes for Payjoin v2 support? Didn’t look in-depth yet, but at least BIP77 contains only the two modes “Base” and “Auth” explicitly (and no mentions of “PSK”): https://github.com/bitcoin/bips/blob/72af87fc72999e3f0a26a06e6e0a7f3134236337/bip-0077.md?plain=1#L286-L287 https://github.com/bitcoin/bips/blob/72af87fc72999e3f0a26a06e6e0a7f3134236337/bip-0077.md?plain=1#L376-L378

  14. w0xlt commented at 6:33 pm on June 4, 2025: contributor

    at least BIP77 contains only the two modes “Base” and “Auth” explicitly (and no mentions of “PSK”):

    Good catch. I still need to verify whether PSK is used by OHTTP in the Payjoin v2 protocol, but since the https://github.com/payjoin/bitcoin-hpke project used by PDK implements and has test vectors for PSK, I added the PSK and AuthPSK modes here as well.

  15. nothingmuch commented at 5:50 pm on June 9, 2025: contributor

    Good catch. I still need to verify whether PSK is used by OHTTP in the Payjoin v2 protocol,

    I can confirm that neither BIP 77 nor the rust-payjoin implementations depend on the PSK functionality. There are ideas for future extensions that might make use of that, but they are only ideas at this point and would not be a part of BIP 77 itself.


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-06-12 21:13 UTC

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