🏗️

Three parties.No single point of trust.

A FrostCard wallet is not one thing — it's three independent pieces that check each other. The card generates and signs. The app builds transactions. The Kaspa network enforces the rules. No app, server, or person can move your money on its own. Here is how the whole system fits together.

See the architecture
Lesson 1
The system is three machines, not one

Most wallets are a single app that holds your keys and trusts itself. FrostCard splits the job across three independent components, each doing one thing — and crucially, each unable to do the others' jobs. Tap below to light them up.

💳
The Card
Generates the key and signs. The private key never leaves it.
NXP J3R200 · EAL6+
📱
The App
Builds transactions, shows balance and history. Holds no secrets.
Flutter · Android + iOS
🌐
The Network
Validates every spend against the on-chain rules. No one controls it.
Kaspa Blockchain
In plain wordsCard generates and signs. App builds transactions. Network enforces rules. Compromise any one alone and the other two stop the attack — that's the whole point of splitting the job.
Component 1
The card — a vault that signs but never tells

The card is an NXP J3R200 smart-card chip — the same class of silicon used in passports, SIMs, and bank cards. It runs an open-source JavaCard applet that handles key generation, BIP-32 derivation, Schnorr signing, PIN, the secure channel, and backup locking.

🔒
What "secure element" actually means
A secure element is a tamper-resistant chip built so a secret inside it can be used but never read out. The J3R200 is hardware-certified to EAL6+ (chip) and EAL5+ as a composite with its JavaCard OS — independent labs have tried to break it and graded how hard it is. Inside: a true random generator, a hardware Schnorr engine, AES, an active shield mesh that wipes on tamper, plus voltage and clock monitors that catch glitch attacks.

The chip holds 150 KB of EEPROM (persistent memory that retains data 25+ years with no power), a hardware True Random Number Generator, and hardware-accelerated secp256k1, AES, SHA-256 and SHA-512. It talks over ISO 14443 Type A NFC at 13.56 MHz — contactless only, no battery, no port.

Why this mattersBecause the secret is born inside the chip and physically cannot be exported, a stolen phone, a malicious app, or a compromised server never has the one thing that can spend your money.
The Conversation
How the card and app talk safely

Every NFC session opens with a key exchange, and from then on everything is encrypted and authenticated. An eavesdropper holding an antenna next to your phone hears only ciphertext. Here is the exact handshake, straight from the applet.

1
Phone offers an ephemeral key OPEN_SECURE_CHANNEL
The phone makes a throwaway secp256k1 key pair and sends its 33-byte public half to the card.
2
Card answers with its own ephemeral key ECDH
The card makes its own throwaway key pair and returns its 33-byte public half. Both sides now compute the same shared secret: ECDH(my private, their public).
3
Derive the session keys SHA-512(secret)
The shared secret is stretched with SHA-512 into a 256-bit AES key (bytes 0–31) and a 128-bit MAC key (bytes 32–47).
4
Everything after this is sealed AES-256-CBC + HMAC
Each packet carries a random 16-byte IV, the encrypted command, and a 32-byte HMAC. PIN verification and signing requests all ride inside this envelope.
5
Burn the keys when you pull the card session ends
The ephemeral keys are destroyed the moment the NFC link drops, so no two sessions are ever the same — and a recorded session can't be replayed.
🤝
ECDH, in one breath
ECDH (Elliptic-Curve Diffie–Hellman) is a trick where two parties each keep a private number, swap only their public halves, and independently arrive at the same shared secret — without ever sending it across the wire. An eavesdropper sees both public halves and still can't compute the secret.
What the channel defeatsEavesdropping (only ciphertext leaks), replay (every session is unique), MITM relay (card attestation binds the session), and tampering (the HMAC catches any altered byte). And no matter what — the private key never crosses NFC.
Component 2 at work
How a payment actually gets signed

Kaspa uses Schnorr signatures over secp256k1 with BLAKE2b-256 sighashes. The heavy lifting — picking coins, building the transaction, hashing it — all happens in the app. The card only ever sees small 32-byte hashes, and you only tap once.

1
App selects UTXOs largest-first
It picks enough coins to cover the amount plus fee.
2
App builds the unsigned transaction inputs · outputs · change
Destinations, amounts, and a change address back to you.
3
App computes per-input sighashes BLAKE2b-256
Each input gets a unique 32-byte hash, domain-keyed with "TransactionSigningHash".
4
Card signs — one tap, all inputs SIGN_HASHES
Over the encrypted channel, the card receives the 32-byte hashes and returns 64-byte Schnorr signatures (R.x ∥ s). The private key takes part but never leaves.
5
App broadcasts → Kaspa
Signatures are inserted into the transaction and sent to the network.
🧾
UTXO and sighash, decoded
A UTXO ("unspent transaction output") is a discrete coin — a chunk of Kaspa sitting at an address, waiting to be spent whole. Your balance is just the sum of your UTXOs. A sighash is a compact fingerprint of exactly what you're authorizing — the inputs, the outputs, the amounts. Signing the sighash signs the whole transaction; change one detail and the fingerprint changes, so the signature no longer fits.
What the card seesNever your transaction in full — only the 32-byte hashes. The BLAKE2b hashing happens in the app, and the chip's single job is to turn each hash into a signature.
One Key, Many Addresses
Every address comes from one master key

FrostCard derives child keys on-card using the standard BIP-32 algorithm. The master key stays on the chip; every address you ever use is a deterministic branch off it.

m / 44' / 111111' / 0' / 0 / index

111111 is Kaspa's registered coin type; index is the address number (0, 1, 2…). Index 0 is your Primary Vault — the only address that gets covenant protection.

🌳
BIP-32, in plain words
BIP-32 is the recipe for growing a whole tree of keys from a single root. Each child is computed by mixing the parent with an index through HMAC-SHA512: hardened steps mix in the private key, normal steps mix in the public key. Because the recipe is fixed, the same master key always regrows the same addresses — which is why a fresh phone can rebuild your whole wallet from one card tap.
Recovery — the gap scanner
Set up a new phone, tap the card, and the app walks addresses in order — idx 0, 1, 2… — checking each one's balance and history. When it hits a run of 20 empty addresses in a row (the standard BIP-44 "gap limit"), it stops. Everything you ever used is recovered deterministically, with no seed phrase to type.
Component 3 — the rules
The network enforces what the card alone cannot
⛓️
What a covenant is
A covenant is a spending rule baked into the coin itself. It's not a setting in the app or a flag on the card — it lives in the UTXO, and every Kaspa node checks it on every spend attempt. No app, server, or firmware can bypass it. Covenants use Kaspa's KIP-10 introspection opcodes — script instructions that let a coin inspect the transaction trying to spend it (its inputs, outputs, amounts, age) and refuse if the rules aren't met.

The script is deployed as a P2SH address. FrostCard compiles three protections into one branching script:

🛡️ Whitelist — trusted contacts  Changeable
Restricts spending to approved destination addresses — the script checks every output against the list with OP_TX_OUTPUT_SPK + OP_EQUALVERIFY. Up to 4 addresses; the first activates instantly, later ones serve a configurable cooling period (default 3 days). Optionally, sends to an unknown address are allowed after a 24-hour cooling-off.
⏳ Inheritance — dead man's switch  Changeable
If the coin sits untouched for a configured period (3–12 months), an heir's key can claim it. The owner path spends anytime and resets the inactivity timer; the heir path requires the inactivity period to pass (enforced by OP_CHECKSEQUENCEVERIFY) plus the heir's signature, and bypasses all other rules.
🧊 Kaspa Freeze — time vault  Permanent
Locks funds until a specific DAA score (block height) via OP_CHECKLOCKTIMEVERIFY. No card can undo it. After expiry the owner retrieves with a cold-key signature, or — if also 6 months inactive — funds fall back to a preset address with no signature needed, the covenant itself enforcing the destination. Requires Inheritance enabled as a safety net.
P2SH, in plain wordsPay-to-Script-Hash means the address is the fingerprint of a rulebook: the covenant address is BLAKE2b-256(script) encoded as a Kaspa address (version byte 0x08). To spend, you must reveal the exact script that matches the hash — and then satisfy it. The rules travel with the money.
Triple-checked before it ever ships
Every covenant passes three independent checks: a Builder compiles the script from your settings; a Decoder rebuilds it from the expected parameters and confirms byte-for-byte equality; and a Simulator runs a stack-based VM that executes every branch against mock transactions before deployment. And the deploy button stays disabled until you've reviewed the decoded script and ticked the confirmation box — what you see is what you sign.
No Paper Backup
The cards are the backup

Because the key is born sealed and never leaves silicon, there are no words to write down. Instead, during setup the key is copied chip-to-chip to your backup cards over an encrypted link — then the whole set is permanently locked.

The backup protocol
The backup card sends LINK_BACKUP phase 1 and returns a 32-byte random challenge. The primary card receives it in phase 2, derives an AES key from SHA-256(challenge), encrypts its private key, and hands back an encrypted bundle. The backup card stores it. A 2-pack makes one backup; a 3-pack makes two.
The permanent lock
LOCK_BACKUP (0x0B) flips an irreversible EEPROM flag. After it, LINK_BACKUP returns SW=0x6985 forever — the flag can't be cleared even by reflashing the applet. The 2 or 3 cards from setup are the only copies of the key that will ever exist.
🗝️
Lose something? You're covered.
Lose your phone → just tap a card on a new one. Lose a card → the others still work. Lose every card → the inheritance covenant hands the funds to your heir. There is no "forgot my card" reset button by design — that path would be a backdoor.
The Whole Stack
Five layers of security, nested

Put the three components together and you get five nested layers. Layers 1–4 answer "can someone get to the key?" Layer 5 answers "even if they do, what can they spend?"

5 · ProtocolKaspa network · covenant enforcement
Stops unauthorized spending even with card + PIN. Enforced by every node.
4 · ApplicationFlutter app · secure storage
Builds transactions, shows WYSIWYS. Holds no private key, never persists the password.
3 · TransportECDH + AES-256-CBC + HMAC-SHA256
Stops NFC eavesdropping, replay and MITM with ephemeral, single-use keys.
2 · JavaCard VMEAL5+ certified sandbox
Memory isolation and type safety stop software exploits inside the chip.
1 · HardwareNXP SmartMX3 · EAL6+
Active shield mesh + voltage/clock monitors stop physical key extraction.
Why "even if they do" mattersOther cards stop at the transport layer — get the key, spend the money. FrostCard adds two layers Tangem can't: a certified VM sandbox (layer 2) and on-chain covenants (layer 5). The covenant means the network itself refuses an unauthorized spend, no matter who holds the card.
Don't Trust — Verify
Every line is public

FrostCard is the first fully open-source NFC cold wallet for Kaspa. The applet that generates and signs, the app that builds transactions, the covenant compiler that writes the on-chain rules — all of it is readable, line by line.

The source — frost-card
The JavaCard applet, the Flutter app, and the covenant builder/decoder/simulator.
The security contract
Keys stay in silicon. Passwords stay in human heads. Everything else is deducible. No single compromise yields funds: card alone can't sign without the password, password alone can't sign without the card, a compromised phone can't misdirect a spend because WYSIWYS shows tampering — and the network's covenant has the final say.
FrostCard — the first fully open-source NFC cold wallet for Kaspa