Never store a CVC (PIN code). Just prompt when needed, and keep in memory
during operation. You should associate it with the card_ident
(card pubkey)
and if a different card is seen, assume a new CVC is needed.
Always verify the factory certificate of the card before trusting any data from it. Otherwise, your users will be tricked by cloned or emulated cards.
chain_code
your code provided, and check that the public key it
gives after picking is derived using that chain_code
. This check applies to
both the SATSCARD, where the path is always m/0
and also the TAPSIGNER,
where you may control the derivation path. On the TAPSIGNER, the xpub
command should return the same chain code as you provided. Verification steps:
cktap setup 123456 -c 17b1987d0d4d8975d38bedbc2ac5142a201d96130fd870244b30a36c1f9f50d3
cktap xpub 123456 -m
xpub661MyMwAqRbcEn7gz6LkGur9F4G3YQ2xEBzr7h8mVxduNox4aDwMWo2QQahtYktGufVkY4jALmLWAHT1iUTBqaYi7jHyRxHEEK94VVhum7D
but yours will be different as private key is generated by cards TRNG. from cktap.bip32 import PubKeyNode
n = PubKeyNode.parse("xpub661MyMwAqRbcEn7gz6LkGur9F4G3YQ2xEBzr7h8mVxduNox4aDwMWo2QQahtYktGufVkY4jALmLWAHT1iUTBqaYi7jHyRxHEEK94VVhum7D")
n.chain_code.hex()
cktap xpub 123456 -m | base58 -d | xxd -p -l32 -s13
cktap setup 123456 -c 17b1987d0d4d8975d38bedbc2ac5142a201d96130fd870244b30a36c1f9f50d3
unseal
commandckcc dump <SLOT NUM>
to see that provided chain code was usedDo not prompt for CVC (PIN code) unless you truly need it. For example, if you are showing the “balance” there is no need for the code. If the user is verifying someone else’s card (for example, before a business transaction is completed), then you’ve risked the funds involved if the CVC is required. In many cases, if you can make the CVC optional you’ve got the best of all worlds: owners of the card, who trust your app, can make use of the CVC and others do not need to.
Highlight when the first slot is unsealed. It is not bad or wrong, but it means that the QR code printed on the card back should no longer be used. The assumption is once a slot is unsealed, the private key is public.
Not all SATSCARD will have a printed QR on the back. For now,
all cards will have the first slot picked at factory, but we may ship
a SATSCARD someday with the first slot unused. In that case, the chain_code
argument to setup
must be provided by your app (32-byte nonce).
When unsealing a slot, you should probably setup the next slot in the same operation. And yet, please handle cards which have no ready-to-use slot: setup the next slot on request.
Although the protocol and library number slots from zero, as programmers prefer, when communicating with users, the slots should start at number one. So externally, they are 1..10 and internally 0..9. When possible, it’s best to say “the first slot” when talking about the QR code on the back and the default settings.
Set the derivation path once, then just add the final two components
(change/not change, and index) when signing digests (see subpath
argument).
Do not try to do anything special with a SATSCHIP if you detect it, just operate like it was a normal TAPSIGNER (because it is, with the exception of the backup command).
Never prompt your user for the AES key printed on the card. It’s for emergencies only and once used, the TAPSIGNER is no longer secure. For backup purposes, capture the data and save it as binary.
Encourage users to change the CVC from factory default.
Treat it just like a TAPSIGNER.
Remember it cannot be backed-up and the keys are known only to the card itself, so consider long and hard before you put big sats under its sole signature.