Solid Crypto Cards
What if crypto could behave like cash?

Solid Crypto Cards was an experiment in turning a cryptocurrency wallet into a physical bearer asset. The idea was simple: put the wallet’s private key inside a secure element, configure it to resist export, and let the card prove that it controls the wallet without revealing the key.

The idea

Normally, transferring cryptocurrency means making an on-chain transaction. I wanted to ask a different question: could ownership of funds at an address be transferred by handing someone the object that controls its key?

The card would contain the wallet key, while the key stayed inside a secure element. Anyone could send funds to its address. A reader could then ask the card to prove possession of the key, and the card could change hands without moving the balance on-chain.

That makes it a proposed bearer instrument only if the holder can trust how the key was created and provisioned. A valid signature alone does not establish that the card is the only copy.

The prototype

The early development board was called OpenACard DEV BOARD 0.1.0. Its responsibilities were deliberately split across three chips:

NFC

NXP PN532

Handles contactless communication between the card and external readers.

MCU

ATmega328P

Runs the application protocol and passes requests between the NFC controller and secure element.

Root of trust

Microchip ATECC608B

Stores the wallet private key and performs cryptographic operations without requiring the key to be exposed to the ATmega.

Reader → PN532 → ATmega328P → ATECC608B

OpenACard DEV BOARD 0.1.0 layout showing the PN532, ATmega328P and secure-element area
OpenACard DEV BOARD 0.1.0 — early Solid Crypto Cards development board.

Verification

The reader creates a fresh random challenge. The PN532 carries it over NFC to the ATmega, which asks the ATECC608B to sign it. The signature returns along the same path. The reader verifies it against the wallet public key.

1 · ChallengeReaderFresh random value
2 · NFCPN532Wireless transport
3 · ProtocolATmega328PForwards request
4 · SignATECC608BPrivate key stays here

The return value is a signature, not the private key. The reader checks verify(public key, challenge, signature); a valid result demonstrates that a key matching the public key signed this challenge.

Why receive-only?

The card did not need to spend funds. Turning it into a normal hardware wallet would add transaction parsing, signing policy, user authorization, output verification, recovery flows and much more protocol state.

Solid Crypto Cards narrowed the intended security-sensitive operation to proving possession of the key. The inability to extract the key was not a limitation. It was the point.

The actual security boundary

The PN532 processes untrusted wireless input. The ATmega runs general application logic. Both can forward a challenge, but neither needs the wallet private key. The ATECC608B offers a smaller cryptographic interface for signing while keeping the configured key inside the chip.

The ATmega does not need the key.
The NFC controller definitely does not need the key.
The reader does not need the key.
So why should any of them ever be able to access it?

Where the trust moves

Challenge-response can show that the card possesses a private key. It cannot prove that no other copy exists. Provisioning and manufacturing therefore become part of the trust model.

Where was the key generated? Could an issuer have copied it before provisioning, or provisioned the same key into another card? A malicious issuer, secure-element compromise, physical attack or compromised supply chain could break the bearer assumption even while every challenge verifies correctly.

The design reduces where the key needs to go during normal use. It does not remove the need to trust the origin and physical security of the card.

What I was actually experimenting with

Solid Crypto Cards began as an attempt to make cryptocurrency physically exchangeable. But the interesting part was the trust boundary. The MCU did not need the key. The NFC controller did not need the key. The reader did not need the key. So the design tried to keep the key away from all three.

← Back to all projects