Beersy
BRC-182

Pairwise Authentication

A BSV wallet normally proves who you are with one permanent key, the same key at every website. That means any two sites you log into can compare and know you're the same person, and you have no way to stop it or start fresh. This makes it possible to have a login that works like a normal account (stable on one site) without becoming a tracking number that follows you everywhere else.

Matthew Archbold16 min read

Reference for an AI

Everything an assistant needs to answer questions about BRC-182 accurately, including what it depends on.

Summary

Why
A wallet's single master lets any two sites that see it link the same user together, with no way for the user to prevent or undo that.
What
BRC-182 defines pairwise authentication: a wallet-derived login key that is unique to each site, built from the user's master key and that site's public key.
How
A developer's site presents its public key during BRC-103 mutual authentication, the wallet derives a pairwise key via BRC-42 using that site's key as and a new `pairwise` flag, and that derived key becomes the stable per-site identity used for login, encryption, signatures and BRC-105 payments.

What this lets you do

  • Log a user in with a key that's stable per site but different everywhere else
  • Add a pairwise flag to existing BRC-100 calls like getPublicKey, encrypt, createSignature
  • Authenticate using unchanged BRC-103 messages and BRC-104 transport
  • Accept BRC-105 payments inside a pairwise-authenticated session
  • Present and verify whose fields are encrypted to the pairwise key

Written by claude-sonnet-5 from the specification text. Where the two differ, the original is correct.

user keysite keyshared secretpairwise key

The specification

Abstract

A BRC-100 (Unified, Vendor-Neutral, Unchanging, and Open BSV Blockchain Standard ) wallet authenticates to every site with the same identity key, its . Any two sites that hold it can tell they have the same user, and the user can't take it back or clear it.

This document specifies pairwise authentication: the wallet authenticates to each site with a key derived from the user's master key and that site's public key. The key is stable at one site, so the user can create an account and log back in. It differs at every other site, so sites can't use it to link the user. It uses existing BRC-42 ( (BKDS)) derivation, the existing BRC-103 (Peer-to-Peer Mutual Authentication and Exchange Protocol) message format and the existing BRC-105 (HTTP Service Monetization Framework) payment headers. What it adds is one wallet-interface flag, a reserved derivation, and the rules a wallet follows to keep sites from choosing the user's key for them.

Motivation

The identity key is the same at every site

BRC-100 calls the master public key the identity key. BRC-103 authenticates a peer by the key in its identityKey field, and the reference SDK fills that field with getPublicKey({ identityKey: true }). So a user who logs in to twenty sites gives each of them the same permanent identifier.

The registry already says this should change, and already names the principle:

"Ordinary authentication should use an application-specific derived key. That identifier should be unique to the defined application context, separate from payment keys, replaceable if the relationship ends and unusable for discovering the user across unrelated services." BRC-151 (BRC-100 Risk Assessment and Best Integration Practices)

"An application domain is not automatically an extra cryptographic separator simply because the wallet knows which application made the request." and "The enduring principle is contextual identity." BRC-191 (Thoughts on Identity, Privacy and Recovery on the Metanet)

No BRC specifies how a wallet does it. This document does.

Why the site's key, and not the site's address

A key derived from the site's public key is the ordinary BRC-42 shared-secret construction: the user's private key and the site's public key give a key only those two parties share. It also makes the site's identity, not its domain name, the thing the account belongs to, which matches how BRC-103 already identifies the site.

Terminology

The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted as described in RFC 2119.

  • Identity key: the wallet's master public key, as defined in BRC-100. The same at every site.
  • Pairwise: one value per pair of parties, so that no third party can link the values used with different counterparties. The term follows OpenID Connect Core 1.0 § 8, which defines public and pairwise subject identifiers. In product copy the same idea is often called site-scoped.
  • Site key: the public key a site authenticates with in BRC-103. It belongs to the site.
  • Pairwise key: the user's key for one site, derived as in § 1. It belongs to the user.
  • Calling domain: the domain the wallet attributes a request to. BRC-100 calls this the originator. Wallets reached by a web page take it from the browser (for example the Origin header), which the page cannot set.

Specification

1. Deriving the pairwise key

The pairwise key is the BRC-42 child of the user's master key with:

InputValue
self
2-admin pairwise-<site key> <version>
  • The invoice follows BRC-43 (, , and Counterparties): security level 2, protocol ID admin pairwise, and a key ID made of the site key (33-byte compressed, lowercase hex), one space, and a version number in decimal. Version 1 gives 2-admin pairwise-<site key> 1.
  • The counterparty is self, not the site key. BRC-42 is symmetric: a key derived from the user's private key and the site's public key can also be computed from the site's private key and the user's public key. With the site key as counterparty, a site could take any identity key it knows, compute what that user's pairwise key would be, and compare it with the key it was shown, unmasking the user without any help from another site. With self, the shared secret comes from the user's private key alone. The site key in the key ID still makes the key different at every site.
  • The protocol ID starts with admin, which BRC-44 (Admin-reserved and Prohibited Key Derivation Protocols) reserves for the wallet's own use. A wallet MUST refuse any application request that names a protocol ID beginning with admin, at every security level. Only the wallet derives the pairwise key, and only through the pairwise flag in § 2. Without this rule, an application could request the pairwise key for any other site and link the user.
  • The version gives a user more than one account at a site. A wallet MAY offer a fresh, unconnected account at the same site by using version 2, 3 and so on. This document uses 1 throughout.
  • Wallets MUST NOT store the pairwise key. It is re-derived on every use.

2. The pairwise flag

This document adds one optional boolean argument, pairwise, to the BRC-100 methods that take a protocolID, keyID and counterparty (getPublicKey, encrypt, decrypt, createHmac, verifyHmac, createSignature, verifySignature) and to each payment output of internalizeAction.

pairwise: true means: perform this operation starting from the pairwise key for the calling domain's site key, instead of from the master key. Every other argument keeps its BRC-100 meaning.

2.1 Recording the site key

  • The first call with pairwise: true from a calling domain MUST be a getPublicKey that supplies counterparty as the site key. The wallet records the pair (calling domain, site key).
  • Every later call with pairwise: true from that domain uses the recorded site key. The application MAY supply counterparty, but it does not change which pairwise key is used.
  • If a getPublicKey call supplies a site key that differs from the one recorded for the domain, the wallet MUST NOT silently replace it. It SHOULD show the user that the site's key has changed, and MUST NOT proceed without the user's approval.
  • If a different calling domain supplies a site key already recorded for another domain, the wallet SHOULD warn the user. Two domains sharing one site key receive the same pairwise key and can link the user.

This is trust on first use: the wallet trusts the first site key a domain presents and holds the domain to it afterwards.

2.2 Rules

  • pairwise: true together with identityKey: true MUST be rejected.
  • pairwise: true together with privileged: true MUST be rejected.
  • A call with pairwise: true discloses no identity key, and wallets SHOULD NOT show an identity-key prompt for it. Wallets MAY apply their usual protocol permissions.
  • A wallet without this extension rejects the first call, getPublicKey({ pairwise: true, counterparty }), because BRC-100 requires protocolID and keyID for a derived key. Applications SHOULD treat that rejection as "not supported" and offer the public login. A wallet MUST NOT answer a pairwise call with the identity key.

3. Account creation and login

3.1 Creating an account

A site offers two buttons: one for a private account and one for an account with the public identity key.

Private account. The page calls:

getPublicKey({ "pairwise": true, "counterparty": "<site key>" })

The wallet records the domain's site key (§ 2.1), derives the pairwise key and returns it with no identity-key prompt:

{ "publicKey": "<pairwise key>" }

Public account. The page calls:

getPublicKey({ "identityKey": true })

The wallet MUST ask the user before disclosing the identity key, unless the user has already approved it for that domain. It returns:

{ "publicKey": "<identity key>" }

The application then runs the BRC-103 handshake (§ 4) with the returned key and creates the account under it.

sequenceDiagram
    participant P as Site page
    participant W as Wallet
    participant S as Site server
    P->>W: getPublicKey({ pairwise: true, counterparty: site key })
    W-->>P: pairwise key
    P->>S: BRC-103 handshake as the pairwise key (§ 4)
    S-->>P: account created for the pairwise key

3.2 Logging in

A site offers one login button. The application tries the pairwise key first:

  1. The page calls getPublicKey({ "pairwise": true, "counterparty": "<site key>" }) and receives the same pairwise key as at account creation.
  2. If the site has an account for that key, the application completes the BRC-103 handshake as that key. The user is logged in with no prompt.
  3. If not, the application SHOULD continue straight to getPublicKey({ "identityKey": true }), without a screen of its own. The wallet's identity-key prompt is the user's check: if the user intended a private login, they deny it and are not logged in.
sequenceDiagram
    participant P as Site page
    participant W as Wallet
    participant S as Site server
    P->>W: getPublicKey({ pairwise: true, counterparty: site key })
    W-->>P: pairwise key
    P->>S: account for this key?
    alt yes
        P->>S: BRC-103 handshake as the pairwise key
    else no
        P->>W: getPublicKey({ identityKey: true })
        Note over W: prompts unless already approved for this domain
        P->>S: BRC-103 handshake as the identity key
    end

Wallets MUST show a prompt before disclosing the identity key, and auto-approval MUST NOT silence it for a domain the user has not approved. That prompt is what stops a page from requesting the identity key behind a button labelled as private.

4. Mutual authentication

Pairwise authentication uses BRC-103 messages unchanged, carried as in BRC-104 (HTTP Transport for BRC-103 Mutual Authentication). The user's identityKey field carries the pairwise key.

{
  "version": "0.1",
  "messageType": "initialRequest",
  "identityKey": "<pairwise key>",
  "initialNonce": "<user nonce>"
}

The wallet operations BRC-103 performs on the user's side carry pairwise: true:

  • Verifying the site. The site signs its initialResponse for the pairwise key. The page calls verifySignature({ ..., "counterparty": "<site key>", "pairwise": true }). The wallet MUST also check that the identityKey in the site's response equals the site key recorded for the calling domain.
  • Signing each request. The page calls createSignature({ "protocolID": [2, "auth message signature"], ..., "counterparty": "<site key>", "pairwise": true }). The site verifies it against the pairwise key exactly as it would against an identity key.

A site's server needs no change to accept pairwise logins: it already verifies whatever key arrives in identityKey.

5. Payments

BRC-105 runs inside a BRC-103 session and treats the session's client key as the payer. Its headers and the x-bsv-payment body are unchanged. Either party can be the sender or the receiver.

Payments follow the key the session authenticated with. The mode is set once, at login, and the client side keeps it for the session. Every wallet call made in a pairwise session carries pairwise: true; SDKs SHOULD add it automatically from the session, so applications don't set it per call. createAction takes no flag: the flag goes on the getPublicKey call that derives the key to pay. A site records and pays an account's key and needs no record of whether that key is pairwise for payments to work. A site MAY store it for its own purposes. Once a payment is internalized, the output carries its own record (§ 5.2), so spending it later doesn't depend on any session.

5.1 Sending

A sender in a pairwise session MUST derive the payment from its pairwise key, by calling getPublicKey with pairwise: true for the payment output:

getPublicKey({
  "protocolID": [2, "3241645161d8"],
  "keyID": "<derivationPrefix> <derivationSuffix>",
  "counterparty": "<receiver's key>",
  "pairwise": true
})

The receiver will look for the payment as coming from the sender's session key. A payment derived from the master key while the session key is the pairwise key can't be found or spent by the receiver. For the same reason, an application MUST report the pairwise key, not the identity key, as the sender's key.

5.2 Receiving

A receiver in a pairwise session marks the output when it internalizes the payment:

internalizeAction({
  "tx": "<Atomic BEEF>",
  "outputs": [{
    "outputIndex": 0,
    "protocol": "wallet payment",
    "paymentRemittance": {
      "derivationPrefix": "<prefix>",
      "derivationSuffix": "<suffix>",
      "senderIdentityKey": "<sender's key>"
    },
    "pairwise": true
  }],
  "description": "<description>"
})

The wallet MUST check that the output pays the key derived from its pairwise key, and MUST remember, with the output, the site key it was received under.

Informative. In practice this is one optional field per output. Outputs without it are ordinary outputs, so existing wallet data is unaffected.

5.3 Spending

When a wallet signs an input that spends an output received under a pairwise key, it MUST derive the signing key in two steps:

pairwise key  = BRC-42 child of the master key,  counterparty = self,   invoice 2-admin pairwise-<site key> 1
signing key   = BRC-42 child of the pairwise key, counterparty = sender,  invoice from the remittance

Each step is ordinary BRC-42. No secret is stored.

5.4 Payments between two users of one site

Two users of the same site can pay each other without either identity key and without a separate message relay. The site passes each user the other's pairwise key and carries the transaction, prefix and suffix inside the two sessions. The sender follows § 5.1 with the receiver's pairwise key as counterparty. The receiver follows § 5.2 with the sender's pairwise key as senderIdentityKey.

sequenceDiagram
    participant A as Sender's wallet
    participant S as Site
    participant B as Receiver's wallet
    S->>A: receiver's pairwise key
    A->>A: derive from sender's pairwise key, pay
    A->>S: tx, prefix, suffix
    S->>B: tx, prefix, suffix, sender's pairwise key
    B->>B: internalizeAction with pairwise: true

5.5 Meeting BRC-151

  • Separate from payment keys. Payments go to child keys derived from the pairwise key. The pairwise key itself never holds funds. It appears only as the sender's key in a remittance.
  • Replaceable. The version in § 1's key ID gives a new, unconnected account.

6. Certificates

  • Sites MAY present certificates in their BRC-103 initialResponse, as BRC-103 already allows. The field-revelation keys are encrypted to the pairwise key, so the page decrypts them with decrypt({ "protocolID": [2, "certificate field encryption"], ..., "pairwise": true }). Wallets MAY verify the , check that the certificate's subject is the recorded site key and check that its is unspent, and MAY show the user the result. Display and certifier trust are left to wallets.
  • Users can't present BRC-52 (Identity Certificates) certificates on a pairwise session without disclosing the identity key, because a names the identity key as its subject. Unlinkable credentials, such as BBS signatures as specified in draft-irtf-cfrg-bbs-signatures and W3C bbs-2023, are a candidate way to prove an attribute on a pairwise session without that key. The proof would be bound to the session, and the pairwise key would remain the user's stable identifier at that site. A full profile is out of and needs to be specified separately.

7. Relationship to other BRCs

  • BRC-151 recommends an application-specific authentication key. This document specifies one.
  • Prior art outside the registry. SLIP-0013 (Authentication using deterministic hierarchy, Pavol Rusnak, SatoshiLabs, 2015) and LUD-05 (BIP32-based generation for auth protocol, LNURL-auth) derive a per-site login key from a secret only the user holds plus the site's identifier, with an index or version for more keys per site. This document follows the same principle using BRC-42 and BRC-43, with the site's public key as the identifier.
  • BRC-228 (Unlinkable Payments under the Identity Paradigm) uses a fresh, random key for every payment, and forbids deriving it from any reusable wallet secret. Pairwise keys are deterministic and stable per site, on purpose, so that accounts survive. The two address different links: BRC-228 hides a payer across payments, and this document hides a user across sites. BRC-191 that a payment made inside a session that already identifies the payer is not made anonymous by changing the payment key. Inside a pairwise session, what the site learns is the pairwise key.
  • BRC-189 (Identity, Certificates, Discovery, and Personal Trust in Applications) allows a person to "choose different keys or wallet profiles for different contexts". This document is one such mechanism.
  • BRC-137 (Device-Aware Wallet Onboarding and Fallback Login for BRC-100 Applications) describes nonce-signature login against the identity key. A site MAY offer both.

8. Security considerations

  • A site that changes its key loses its pairwise accounts. The pairwise key depends on the site key, so a new site key gives every user a new pairwise key. Sites SHOULD treat their key as long-lived. Section 2.1 makes the change visible to the user rather than silent.
  • Sites that share a key can link users. Two domains presenting one site key receive the same pairwise key. Section 2.1 tells wallets to warn when they see it.
  • The calling domain must come from the browser, not the page. A wallet that accepts a domain supplied by the page lets one site claim to be another and read its pairwise key.
  • The pairwise key must not be computable by the site. Section 1 derives it with counterparty self for this reason. A derivation that uses the site key as counterparty lets the site test any known identity key against a pairwise key and unmask the user.
  • The admin reservation is load-bearing. A wallet that lets applications derive admin protocols gives any page every pairwise key. Section 1 makes refusal a MUST.

9. Privacy considerations

Unlinkable here means: two sites can't use the pairwise key to tell they share a user, and one site can't use it to connect a user's pairwise account with a public account the same user holds there. It does not hide the user from the site they are logged in to, from a certifier that issued them a credential, or from analysis of the transaction graph, where inputs and change still belong to the same wallet.

10. Test vectors

Generated with @bsv/sdk 2.8.11 using fixed test keys. These private keys are public: never use them for funds. All hex is lowercase; public keys are compressed.

Pairwise key (§ 1)

Value
User 0000000000000000000000000000000000000000000000000000000000000011
User identity key03defdea4cdb677750a420fee807eacf21eb9898ae79b9768766e4faa04a2d4a34
Site private key0000000000000000000000000000000000000000000000000000000000000022
Site key031be68a5a028f2601d0e80d468c344ba331d611b96c358b6032e8b4da0547fc11
Counterpartyself
Invoice2-admin pairwise-031be68a5a028f2601d0e80d468c344ba331d611b96c358b6032e8b4da0547fc11 1
Pairwise private key12edeafb17aab433a6e958c014ba08974eb9ddba0540b9f8c8d44cb36888efff
Pairwise key037be3648196bec37bb1eaf3af0d8b654d418f0230e6012ca25a315787afc33d46
Pairwise key at a second site (site key 0270e6b44a2ac6083ab673bacb5cb7ca554b795b416e702c1c980bb7b87c78b8e9)037bd821cb8312292ecfa1bc08670d4202f1893dd69465146e6e50d54dbd232358

Payments (§ 5), protocol [2, "3241645161d8"], prefix cHJlZml4, suffix c3VmZml4

Value
User pays site: output key036a823a3bdd9d9ef02bdbcd3becdec4862f58d3caded84171105a7043d451cdab
Site pays user: output key02b03eb26a51d47abdbf683ec7678b64b9c47fb4de554255d20ea4df992488f7db
Site pays user: user's two-step spending private keyc1198013b3d38739d26908f2fe2a3805a371cd658c5ef82724fa9573af8ff2b5

Payment between two users of the site (§ 5.4)

Value
Receiver master private key0000000000000000000000000000000000000000000000000000000000000033
Receiver pairwise key033f4d8d7ad66fc08440309a720aee9bd17b6709faeac3dfe033d1d077e3087053
Output key (sender = the user above, from its pairwise key)032c0befee26bf0b89610cd212d818f601688755b5f6ed7b1d439f7d133117b793
Receiver's two-step spending private key6b6b85a998c2a0df423acdbb4d27479e88c10daf375008964f613dbf7fc8fee1

Checks an implementation should reproduce.

  • The site cannot compute the pairwise key from the user's identity key: deriving with protocol admin pairwise, the same key ID and the identity key as counterparty gives a different key.
  • A login signature made from the pairwise key verifies at the site, and the user verifies the site's signature from the pairwise key.
  • An made from the pairwise key verifies at the site, and the user decrypts from the pairwise key what the site encrypted to it.
  • Each of these fails when the master key is used instead. A payment derived from the master key is not the key the receiver looks for, and a one-step spending derivation does not match the output.

11. Open questions

  1. Discovering the site key. This document has the page supply it on first use. A site could also publish it at a well-known address so a wallet can confirm it.
  2. Domain granularity. Whether shop.example.com and example.com count as one calling domain.
  3. Moving a site key. A signed statement from the old site key over the new one would let wallets follow a planned change without a prompt.

12. Implementations

None yet.

13. Acknowledgements

Thanks to Bridget Doran for pointing out that payments received under a pairwise key could not be spent without further wallet support, and that deriving the pairwise key with the site key as counterparty would let a site unmask users from known identity keys.

References

  • BRC-42: BSV Key Derivation Scheme (BKDS)
  • BRC-43: Security Levels, Protocol IDs, Key IDs and Counterparties
  • BRC-44: Admin-reserved and Prohibited Key Derivation Protocols
  • BRC-52: Identity Certificates
  • BRC-100: Unified, Vendor-Neutral, Unchanging, and Open BSV Blockchain Standard Wallet-to-Application Interface
  • BRC-103: Peer-to-Peer Mutual Authentication and Certificate Exchange Protocol
  • BRC-104: HTTP Transport for BRC-103 Mutual Authentication
  • BRC-105: HTTP Service Monetization Framework
  • BRC-137: Device-Aware Wallet Onboarding and Fallback Login for BRC-100 Applications
  • BRC-151: BRC-100 Risk Assessment and Best Integration Practices
  • BRC-189: Identity, Certificates, Discovery, and Personal Trust in Applications
  • BRC-191: Thoughts on Identity, Privacy and Recovery on the Metanet
  • BRC-228: Unlinkable Payments under the Identity Paradigm
  • OpenID Connect Core 1.0, § 8 Subject Identifier Types
  • SLIP-0013: Authentication using deterministic hierarchy, https://github.com/satoshilabs/slips/blob/master/slip-0013.md
  • LUD-05: BIP32-based seed generation for auth protocol, https://github.com/lnurl/luds/blob/luds/05.md
  • RFC 2119, Key words for use in RFCs to Indicate Requirement Levels
Was this helpful?

Search Beersy

Search standards by number, title, author or topic