bips
bips copied to clipboard
BIP 77: Payjoin Version 2 — Async Payjoin
This document proposes an asynchronous, backwards-compatible second version of the payjoin protocol described in BIP 78, enabling complete payjoin receiver functionality including payment output substitution with only an HTTP client rather than server. The former requirement for receivers to run HTTP servers is replaced with an untrusted third-party "payjoin directory" store-and-forward server accessed by polling clients which communicate using an asynchronous protocol and authenticated, encrypted payloads. It was originally proposed to the mailing list here.
The protocol design has received rounds of review elsewhere on the bitcoin-dev mailing list as well.
Feedback from that list post has been incorporated into this draft.
Proposing this as an Standards Track BIP to ensure wallets across the ecosystem can come to rough consensus on a single asynchronous payjoin standard and correctly implement it widely.
Let's call this BIP 77
Hi @DanGould, the first comment on this PR seems to indicate that this proposal is still WIP. Is that an accurate understanding? If this PR is not yet ready to be merged, perhaps it should be changed to "Draft". If I misunderstood the status of this PR, please respond below so someone may review to assess whether this is ready for merge.
Converted to draft until we have some more experience with the implementations in the wild.
Still seeking review especially on the soundness of the network privacy, choice of cryptosystem, and bip21 parameter encoding.
@jonatack Thank you for the review and implicit advice about how to clarify technical specifications such as this one with even small changes like using explicit subjects. Your patient, thorough contribution moves the needle toward production readiness and helps me reflect on the parts of the spec that are most lacking to correct them.
In incorporating your fresh perspective, I see a few issues remaining that I'll outline as a note for myself to correct:
- [x] Revise document to describe Payjoin "sessions" instead of directory "enrollment". e.g.: "The payjoin version 2 protocol uses per-[session] public keys"
- [ ] Replacethe
Authenticate: <token>messaging with a mask on eligible OHTTP relay addresses that start with "pay" domains. Avoid using identifying protocols like authentication tokens to preserve privacy. The goal is to make free access to these servers while by limiting their capability to preventing DoS vectors or misuse. - [ ] Either include PSBTv2 in the reference implementation or remove it from the bip77 spec
I really enjoyed reading this :) Well done! Dropped some comments on mainly nit related suggestions, but there were a few places where I left comments seeking clarification.
Hi @DanGould, want to update here?
Hi @DanGould, want to update here?
Since the last review I have made breaking changes, which I'll apply with an update now. I think we're at the point where each design decision I'm aware of is deliberate. I'll take it out of draft once the new update is pushed.
The main changes from the last review are that
- HTTP request methods (POST, GET, PUT) control the flow of the protocol rather than further path subdiretories
- bip21 parameters (pj subdirectory and ohttp key config) serialize as compressed public keys to shorten the URI
- Use PSBTv0 since PSBTv2 support is still very limited
- explicitly mention the format of the
ohttpKeyConfiguration URL fragment
NACK
This BIP is bad for privacy
Can you provide the reasoning, please?
NACK
This BIP is bad for privacy
Can you provide the reasoning, please?
Risks with accepting donations using payjoin:
- Probing: Already mentioned in BIP 78
- Small donations: Best form of attack in which FBI donates some sats to support their work and know all the UTXOs in the wallet
Example: https://hrf.org/payjoin
Risks with accepting donations using payjoin:
- Probing: Already mentioned in BIP 78 but BIP 77 author too emotional to accept it
- Small donations: Best form of attack in which FBI donates some sats to support their work and know all the UTXOs in the wallet
@1440000bytes Your first point has already been addressed and he has added a link to the attack vectors section on BIP-78. No one is "not accepting" anything. Are you asking that the full explanation given on probing attacks in BIP-78 be redundantly added here? What exactly is your criticism?
Your second point has already been addressed in BIP-78, here is what the link that you suggested be added says:
While we cannot prevent this type of attack entirely, we implemented the following mitigations:
- When the receiver detects an original transaction being broadcast, or if the receiver detects that the original transaction has been double spent, then they will reuse the UTXO that was exposed for the next payjoin.
- While the exposed UTXO will be reused in priority to not leak other UTXOs, there is no strong guarantee about it. This prevents the attacker from detecting with certainty the next payjoin of the merchant to another peer.
BIP-78 already explains what can be done to mitigate this, and fully acknowledges this tradeoff. Can you explain, in terms of probing attacks, how BIP-77 would be worse for privacy than the already accepted BIP-78?
The sender could first register an additional session subdirectory for the response, and include the associated public key along with the original PSBT when posting to the receiver's subdirectory. The sender would then respond in the sender's subdirectory.
Eliminating the request/response distinction would avoid a metadata leak, namely whether or not the payjoin flow was completed, since requests and responses would be indistinguishable.
A followup suggestion would be removing explicit session initialization. Incidentally in the reference directory it appears that since post_session is stateless, calling it before other operations is indeed not enforced. GET & POST handlers do appear to validate the id path component, but if they did then the first successful request would indicate to either party that the subdirectory ID is valid (or perhaps arbitrary IDs were allowed by design?)
Timing analysis of subdirectory polling could still leak information about which payjoin requests were responded to, but aggressive clients could mitigate this by maintaining a pool of pre-allocated and randomly polled subdirectories ahead of time, and by responding to themselves in some of them with dummy payloads to generate random cover traffic.
@nothingmuch I'll write up your suggestions to simplify the protocol. It makes the directory implementation simpler, requires fewer protocol message types, and even reduces bandwidth. wowza
The sender could first register an additional session subdirectory ... and include the associated public key along with the original PSBT
HPKE E2EE deployed in this application in Authenticated mode (akin to Noise Framework's IK model) already requires the sender to include their session public key as associated data, so this is an pretty darn easy change to make. The change not only simplifies the protocol messaging, but as you say eliminates a metadata leak. I'm a big fan.
A followup suggestion would be removing explicit session initialization
This makes sense too. Creating separate subdirectory resources for either sender or receiver on POST then GETting updates to replace the repeated sender POST polling reduces bandwidth too, since the GET request doesn't contain that repeat POST body.
Even without aggressive client mitigation of the remaining client leaks subject to timing analysis assuming this suggestion is put in place, your new design deletes complexity and improves efficiency.
I'll update the BIP to the best of my understanding based on your comment and link it to a rust-payjoin issue to implement. This spec has already made some breaking changes since the last directory release, so it's a good time for another one since we won't break production implementations other than our own.
Edit: Is there a potential authorization issue now that the sender POSTs first? In the current design of the protocol, only the receiver might need authorization from the directory in order to initialize a session subdirectory, and having knowledge of a session public key was sufficient for the sender to use an initialized subdirectory. Now, the sender would also need to obtain authorization somehow, since the directory doesn't yet know about the session the receiver has implicitly initiated by communicating directly with the sender, out of band from the directory. We'll have to work out how this might affect the expiration mechanic as well.
Would be great to move this draft forward. Relevant blog post and discussion yesterday:
- https://payjoindevkit.org/2025/03/18/the-evolution-of-payjoin/
- https://x.com/jonatack/status/1902786993416781852
Would be great to move this draft forward. Relevant blog post and discussion yesterday:
* [payjoindevkit.org/2025/03/18/the-evolution-of-payjoin](https://payjoindevkit.org/2025/03/18/the-evolution-of-payjoin/) * [x.com/jonatack/status/1902786993416781852](https://x.com/jonatack/status/1902786993416781852)
Last updates here were 3 months ago, if I'm not misreading. Pinging BIP author @DanGould.
@nothingmuch and I have been revising behind the scenes over the past 2 weeks. Have not forgotten. Update coming soon
Hi @DanGould, I see you've pushed an update. Can you let us know when it is ready for review and what changed (thanks!)
A major rewrite touched every section of the document and reorganized the hierarchy. This is ready for review.
- abstract introduces what and why
- motivation touches on the privacy risk satoshi left in the whitepaper as well as how the solution can make more efficient batches and the limitations of v1.
- Overview, Basic Scheme, and a procedural list were consolidated into a single overview which links to ordered specification sections
- specification sections appear in procedural order for easier reading
- Much rationale was moved out of specification and into specific rational subsections
- sequence diagrams are rendered in
mermaidfor better semantic clarity in source and in render - version 2 specifics like directory OHTTP gateway
allowed_purposesadvertisement, expiration, fragment parameters, HPKE info strings. were edited for completeness. - complete document was edited for clarity under recitation, the way each sentence sounds.
The document was rewritten with @nothingmuch so that an implementer or anyone who wants some education on the subject can read through an ordered hierarchy of detail they find relevant. Thank you for your patience on this edit.
@murchandamus I've addressed your comments except for some of those to which I left replies.
Thanks for the thorough review
I'd missed some comments and so addressed those as well as the new ones
@jonatack I believe I've addressed each of your comments in this last review. Thanks for the useful feedback. Your polish really elevates the reading experience.
Addressed comments requiring @jonatack's feedback, decided to stick with BIP 21 since that's the lowest common dependency, and imposed a requirement on fragment parameter order since it might impose a fingerprint (thanks @murchandamus for bringing up the consideration of parameter order).