What two CoinCards prove to each other, what that permits, and what it does not yet do.
The short answer. Binding is mutual proof of possession: each card signs a fresh nonce supplied by the other, so each side learns that the other controls the private key for the public key it claims. It is not a shared secret and not an encrypted channel. Those are the next step, and this page is explicit about the difference.
| Step | Who acts | What is produced |
|---|---|---|
| 1 · connect | either party | A room. Both accounts are in it; who is who is recorded. |
| 2 · direction | each party | intent = send or get. Opposite intents are
what make a transfer legal. |
| 3 · nonces | each party | A 32-byte random nonce per side, stored against the connection. |
| 4 · sign | each card | Card A signs B's nonce; card B signs A's nonce. Signatures are ECDSA over SHA-256, produced on the chip. |
| 5 · verify | service | Each signature is checked against the card public key on file for that account.
Both verified ⇒ mutual: true. |
Once mutual is true the service records that this pair of cards proved each
other. What it is then used for is a policy decision, not a cryptographic one: it is what
distinguishes a transfer to a known, proved counterparty from a transfer to an arbitrary
recipient.
| Property | Why it follows |
|---|---|
| A card cannot be impersonated in a binding | The signature only verifies under the key enrolled for that account, and the key never leaves the chip. |
| A binding cannot be replayed | Nonces are random and single-use; a captured signature does not verify against a new nonce. |
| A transfer has a proved counterparty | The receiving card signs before value moves, so "who is on the other end" is answered by the chip rather than by a handle typed into a field. |
| The tunnel/custody choice is informed | Card-to-card transfer requires mutual proof; without it, value moves under custody and is recorded. |
Both cards already hold P-256 keys, so a genuine pair-wise channel needs one extra step at bind time:
shared = ECDH(myCardKey, theirCardKey) // same on both sides, unknown elsewhere key = HKDF-SHA256(shared, salt = nonceA||nonceB, info = "coincard-channel-v1") payload = AEAD-Seal(key, token64, nonce = random 12 bytes)
Requirements that make this worth doing rather than decorative:
Status. Implemented: nonces, card signatures, verification,
and the policy use of mutual. Not implemented: key agreement, message encryption,
payload chaining. Until those exist, card-to-card transfer of a token's payload is a design,
and a send moves value under escrow custody — which is recorded, reversible only by
redemption, and visible in the issuer's ledger.
The separation is what makes the mechanism auditable. A binding is evidence — a signature a chip produced over a value nobody could predict — and evidence can be stored, re-checked and disputed. A shared key is a secret, and a secret nobody can inspect is a promise. CoinCard keeps the first for its records and only introduces the second where confidentiality of the payload is genuinely required.
Sandbox deployment, USD, English. Values shown elsewhere in the system are test values and are not money. This page describes implemented behaviour; the section on the encrypted channel describes intent and is labelled as such.