Hi all,
In anticipation of future Zero-Knowledge Proof (ZKP) Bitcoin Cash covenants, I’ve been reviewing how to make implementation in wallets as practical and private as possible.
I expect now that many ZKP covenant systems can be fully supported by generalized “wallet engine” infrastructure, such that software which supports wallet templates will be able to simply import and use ZKP covenant wallet templates (create a wallet, scan for matching UTXOs, and deposit, transfer within, and withdraw from public ZKP covenants) with minimal integration work.
However, the Bitcoin Cash P2P protocol has two areas requiring improvements for better privacy in real-world usage:
-
Transaction origin exposure – network-level adversaries can trivially identify the node which first broadcasts most transactions. Many end-user wallets are partially protected from network-level monitoring by broadcasting via a backend controlled by their wallet vendor or community-run Fulcrum servers (Electrum protocol), but this comes at the cost of leaking far more actionable data to those providers (who in many cases are also servicing “balance checks” and other queries that reliably de-anonymize all of the end-user’s activity).
-
Cleartext network communications – the Bitcoin Cash P2P protocol does not support any form of encryption, so network-level adversaries can very easily identify and track all activity, simplifying and lowering the cost of both censorship and attacks on privacy.
Some ideas I’ve reviewed:
A new “ONION_TX
” P2P protocol extension
We could add a Tor-like transaction broadcast protocol where the transaction is encrypted to a path of known “onion-capable” nodes. However, powerful network-level attackers could likely still correlate traffic in and out of circuits with timing analysis – at the very least, much of the rest of the network would need to upgrade to encrypted connections as well.
Additionally, it’s very hard to protect against denial-of-service attacks: even if nodes temporarily remembered onion TXs they forwarded, and we added a backwards-propagating ONION_ABUSE
message to allow nodes in the circuit to blame a misbehaving node, the originating node may always plausibly claim to be a victim of an earlier non-existent node. Compare that with our existing protocol, which is very byte-efficient at banning misbehaving peers for wasting bandwidth on invalid transactions. (And of course transaction fees impose a cost on valid transaction bandwidth.)
Note also that BCH nodes can already connect via Tor, which probably offers both better privacy and greater resistance to denial-of-service attacks (due to the size of the existing Tor network).
TLDR: An “onion” extension would be complex, easily abused, and ultimately less private than network-layer encryption + a deniable broadcast solution (Dandelion++ or Clover).
BIP324 opportunistic encryption
Bitcoin Cash nodes could implement BIP324, an upgrade to add encryption to the existing P2P protocol.
If our only goal were to better protect traffic against powerful network-level adversaries, this solution seems hard to beat: maximally simple, pseudorandom bytestream, shapable for better censorship resistance, etc.
However, implementation is not trivial: it’s a new, special-purpose protocol with relatively little ecosystem support (some scattered patches for various BTC software, early support in a few BTC-only libraries).
It’s quite hard to justify this additional work and maintenance when compared to adopting a more widely-used stack like Noise or libp2p, for which better-reviewed libraries already exist in a variety of language/programming environments.
Further, even if encryption support were successfully deployed to 100% of BCH nodes, we’d still need solutions for transaction origin exposure – well-connected adversaries could still trivially identify originating nodes on the main network, and the status quo of wallets leaking private info to backend servers would remain unchanged.
In fact, even coupled with a deniable broadcast solution like Dandelion++ or Clover, practical privacy for most end-users would still remain highly vulnerable to trusted backends. To create plausible deniability in light client transaction broadcast, you need the light clients to also be plausibly participating in the deniable broadcast protocol, i.e. light clients with peer connections to other nodes and light clients.
Implementing BIP324 would bring encryption to the existing P2P network, but it wouldn’t improve the privacy of most light wallets – for that we need to make it easier for light wallets to broadcast transactions directly over the P2P network (even if they still leak other info to backend servers rather than internally running pruned or SPV nodes).
TLDR: a partial solution to cleartext P2P communications, but at significant implementation cost, with little new practical privacy for most light wallets users.
Proposals for Bitcoin Cash
With that background, I’d like to outline some solutions I’m exploring.
These might eventually become CHIPs to make them easier to talk about, but note that they’re much “lower-stakes” than VM changes: there’s no consensus or widely-coordinated upgrade needed here, nodes and wallets can choose to start or stop speaking protocols whenever they like, and it’s likely we’ll iterate a bit.
Implement PTX
messages (“Clover”)
In my opinion, Clover is a clear improvement over Dandelion++ – it’s simpler, faster, more byte efficient, has fewer pitfalls, and offers overall better privacy to all network participants.
In short: nodes add a new PTX
(“proxy TX”) message type equivalent to the TX
type, but quietly relayed based on some simple rules such that the network first “hears” it via the standard INV
diffusion after a few hops.
When performed across encrypted connections, this offers similar privacy to an “onion” extension, but without the denial-of-service issues. Note that even the first peer to receive the PTX
can’t know if the originator was simply forwarding it, so they learn only slightly more than if they were passing along an onion-encrypted payload. However, with the payload visible, they 1) are not wasting bandwidth (they won’t need to GETDATA
the TX again later) and 2) can easily see if it’s invalid and ban misbehaving peers.
Without encryption, the originator of each PTX
message is still easily tracked by powerful network-level adversaries, but when combined with some P2P layer encryption solution (and perhaps if messages are padded to a fixed length), we get Tor-like privacy without the DoS exposure.
One BCH-specific detail: nodes must advertise in service bits whether or not they support PTX
, and only forward PTX
to other supporting nodes. With BCH’s annual upgrades, we’re likely to have great support relatively quickly, but it’s important that PTX
“support” remains optional (e.g. Chaingraph probably won’t implement the PTX
forwarding behavior, so if nodes blindly selected a Chaingraph agent to send a PTX
, propagation would be delayed until a previous node’s timeout was triggered.) Some node implementations will never bother to implement, and that’s fine.
Implement optional libp2p
transport protocols
The libp2p project seems to have come a long way in standardizing various transport protocols, implementing native libraries in a variety of languages, and resolving earlier resource exhaustion issues. A number of cryptocurrency projects now use libp2p, including Ethereum since 2023.
I’d love to see BCH node implementations experiment with using libp2p libraries to support the TCP + Noise + Yamux, WebTransport, and WebRTC libp2p transport protocols. This would unlock P2P network compatibility with the web platform, enabling:
- Web-based peers that can easily contribute bandwidth from any connection (like Tor’s Snowflake project),
- Stronger censorship resistance: more protocol options to route around censorship/damage, and BCH traffic can blend in with video calls (WebRTC) and HTTP/3 (WebTransport),
- Strongly-private, PWA-based nodes and severless wallets,
- Simpler, JS-only P2P connection code in web-stack based software (e.g. wallets built with Electron, Tauri, Expo, React Native, Capacitor, etc.)
Rough sketch of the necessary parts:
- Reuse most of existing P2P message formats after libp2p handshakes – can simply remove the checksum field (as the transport layers handle message integrity). The
addr
message format would continue to enable “v1” P2P discovery. - Extend the existing
version
handshake to enable immediately upgrading to libp2p WebTransport for the performance and encryption, or libp2p TCP for the encryption. - Seeder support for JSON responses – we need some seeder (like BCHN’s) to support listening on a port and returning the list via HTTP in JSON format. (Seeder operators should also set up HTTPS with Caddy or something.) The JSON response should only include nodes with libp2p interfaces enabled (and returned records should allow for opening WebTransport and/or WebRTC connections).
Long term, I hope to add support in Libauth for locally running a fast-syncing pruned node in the browser, Node.js, Deno, Bun, etc. such that Libauth-based wallets can both participate in PTX
(“Clover”) broadcasting and scan for their own UTXOs without leaking info to backends (at the cost of local storage and bandwidth usage). Clients running in Node.js, Deno, or Bun would bridge between v1 P2P nodes and libp2p-connected nodes to help bootstrap the libp2p-based network (stretch goal: a PWA and/or browser extension-based full node with support for ~1MB sub-block progressive knockout filters).
Does anyone see areas for improvement over PTX messages + encrypted libp2p transports?