Abstract
This BRC lets two online wallets, or two installs of one account, send BRC-33 messagebox traffic over a direct WebRTC data channel. It uses the connection that webrtpay/1 (WebRTPay protocol reference) defines for direct payments, unchanged: the same signalling envelopes, presence check, channel framing and identity handshake. It adds only what messages need: a messages purpose, device addressing for installs that share an identity key, and two session messages, msg and ack.
The messagebox stays the meeting point and the offline inbox. The channel carries the same message bodies the box would. It never carries custody.
Motivation
A messagebox exists because the other wallet is often offline, firewalled, or unable to keep a listener. When both wallets are online, sending every chat line, remittance card and coordination message through a store-and-forward host only adds delay.
webrtpay/1, shipped as @bsv/webrtpay in the BSV TypeScript stack, already handles the hard parts for payments: NAT traversal, a presence check that answers in about two seconds, end-to-end encrypted signalling, a channel bound to both identity keys through BRC-100 signatures, an optional relay and TURN. A second protocol for the same connection would split wallets into two groups that cannot reach each other. This BRC reuses that connection and defines only the messaging layer.
Relationship to other documents
| Concern | Document |
|---|---|
| Connection: signalling envelopes and their encryption, knock and ring, ICE, channel framing, identity handshake, relay | webrtpay/1 (reference) §3 to §5, §7 to §9 |
| Messages carried | BRC-33, each body sealed per BRC-78 |
| Keys and signatures | BRC-100 |
| Coordination between installs of one account | Draft BRC-249 (#311) |
Section numbers such as webrtpay/1 §7.4 refer to the reference at the commit linked below.
Specification
The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" are to be interpreted as described in RFC 2119.
1. Scope
This BRC covers messages that already travel over BRC-33: chat, remittance cards, token deliveries and similar notices, and coordination between installs of one account such as BRC-249 release requests. It does not cover coin selection, signing or broadcast. An on-chain output remains the only proof of payment or item custody. A payment by itself uses webrtpay/1's payment purpose, not this one.
2. Endpoints
An endpoint is one install: an identity key and a device, a random identifier of 1 to 128 characters from [A-Za-z0-9._-] that the install keeps for its lifetime. Two endpoints may share an identity key, as installs of one account do; they MUST then differ in device. The device SHOULD NOT be derived from any key or hardware identifier.
3. Signalling
Signals are webrtpay/1 signalling envelopes (§7.1 to §7.3), encrypted with BRC-100 encrypt under protocol [2, "webrtpay signaling"] exactly as there, with these differences:
- Purpose. The plaintext's
purposeis"messages". - Devices. The plaintext carries
fromDevice, the sender's device, andtoDevice, the recipient's device. In aknockorofferto another identity,toDeviceMAY be empty, meaning whichever install answers. It MUST be set whentoequalsfrom, and in everyring,answerandreject, where it is the dial'sfromDevice. - Box. On a messagebox carrier, signals go in box
webrtpay_messages, never inwebrtpay_signals. A wallet that implements only payments never lists that box, so it never decrypts a signal it would refuse. A relay carrier (webrtpay/1§8) carries them unchanged.
A receiver opens a signal as webrtpay/1 §7.4 does, accepting purpose "messages" in step 2 and checking the device fields before anything else:
- It ignores a signal whose
fromis its own identity and whosefromDeviceis its own device. - It ignores a signal whose
toDevicenames another device, and MUST NOT acknowledge it on the messagebox, so the addressed install still finds it. - It acknowledges every other signal once it has processed it.
Installs that share an identity share its box. An install applies these rules even when it cannot open a data channel, so it never consumes a signal meant for another install.
4. Dialing and admission
Dialing follows webrtpay/1 §7.5: knock, ring, offer, answer, with its presence and dial timeouts and its network binding. A dial that ends peer_unreachable, timeout or rejected sends its messages through the messagebox.
When the messagebox is polled rather than pushed (BRC-33 listMessages), a reply comes only after the peer's next read. A dialer on such a carrier adds the peer's poll interval to both the presence and the dial timeout. A polling wallet reads its signalling box at least every 2.5 s while it receives and every second while it dials.
A wallet SHOULD ring and answer only identities the user has exchanged messages with, and its own installs, and otherwise answer a knock with reject not_receiving or not at all. Intake limits follow webrtpay/1 §7.6.
An endpoint has at most one messages session with another endpoint. If installs of one account dial each other at the same time, the one whose identityKey + "\n" + device sorts lower keeps its dial and the other answers it.
5. Session messages
After the identity handshake (webrtpay/1 §5), the session carries webrtpay/1 frames (§4) whose objects are:
{ "t": "msg", "id": "<1–64 characters>", "body": "<the body the messagebox would have carried>" }
{ "t": "ack", "id": "<the msg id>" }
and webrtpay/1's error and bye (§6.4). Any other t is a protocol error, as in webrtpay/1 §6.
- The receiver MUST pass
bodyto the same ingest path as a messagebox message from the identity the handshake proved, and sendackafter ingest accepts it. - A
msgMUST NOT exceed 256 KiB; a larger body goes through the messagebox. - If the sender receives no
ackwithin one second, it MUST close the session and send that message through the messagebox. A body can therefore arrive twice, once per path, so ingest MUST treat a repeat as it treats a repeated messagebox delivery. - An
ackacknowledges delivery of a message, never a payment.
6. Lifetime
A session ends when its channel closes, ICE fails, or either side sends bye. Messages then go through the messagebox until a new dial completes. A wallet SHOULD close a session that has been idle for ten minutes, and MUST close its sessions when it locks or switches account.
7. What this is not
- Not a replacement for BRC-33. First contact, offline peers and failed dials use the messagebox.
- Not a custody channel.
- Not history sync. Installs of one account may hold a session to carry coordination messages, not to merge state continuously.
- Not a listener requirement. Neither side opens a port.
Security considerations
- Authentication and encryption are
webrtpay/1's: each side signs a transcript of both DTLS fingerprints, both nonces and both identity keys with a BRC-100 key, so a messagebox host, STUN server or TURN relay cannot read or redirect the channel. Eachbodyalso keeps its own BRC-78 envelope, as on the box. - Address exposure. An offer or answer reveals the sender's public address, and possibly local ones, to its recipient only, since signals are encrypted to it.
webrtpay/1gathers no ICE before a ring, so a knock discloses nothing. STUN servers learn a wallet's public address; a TURN relay learns both endpoints' addresses and sees only encrypted traffic. For this reason §4 limits who is answered. - Abuse. Anyone can post signals to a wallet's
webrtpay_messagesbox. Answering only known identities, andwebrtpay/1's intake limits, bound the work.
Rationale
- Why build on
webrtpay/1. It is the WebRTC connection the BSV stack ships, with a byte-level reference and test vectors. Reusing it gives one connection for payments and messages, one handshake to audit, and wallets that work together. - Why a separate purpose and box.
webrtpay/1receivers refuse any purpose butpaymentand close on unknown session messages. A separate purpose and box leave payment-only wallets untouched. A wallet that implements both can route each signal without trial decryption. - Why devices. Two installs of one account have the same identity key. The device tells them apart in addressing, in simultaneous dials and in acknowledgement. That is what lets BRC-249 coordinate a move over a direct session.
Implementation
@bsv/webrtpay (bsv-blockchain/ts-stack) implements the connection. HandCash Desktop and Mobile implement an earlier revision of this BRC, which signed session descriptions directly, and are moving to this one.
References
webrtpay/1: WebRTPay protocol reference,@bsv/webrtpay- BRC-33: PeerServ Message Relay Interface
- BRC-78: Serialization Format for Portable Encrypted Messages
- BRC-100: Wallet-to-Application Interface
- Draft BRC-249 (#311): Vault Account Holding Across Devices
- RFC 8445: Interactive Connectivity Establishment (ICE)
- RFC 8831: WebRTC Data Channels