16 Oct 2026

  • CLA = 0x80
  • INS = 0xC0
  • P1 = 0x01
  • P2 = signing algorithm
  • Data = the hash to sign (32 bytes) | tweak (32 bytes, only if P2 = 0x03) | sequence of 32-bit integers
  • Response = signature
  • Response SW = 0x9000 on success, 0x6A80 if the data is shorter than the algorithm requires, 0x6A86 if P1 or P2 are invalid, 0x6A81 if the algorithm specified in P2 is not supported
  • Preconditions: Secure Channel must be opened, user PIN must be verified, a valid keypair must be loaded

P2:

  • 0x00: ECDSA over secp256k1
  • 0x01: EDDSA over ed25519 (reserved, not implemented)
  • 0x02: BLS12-381 (reserved, not implemented)
  • 0x03: BIP340 Schnorr

Note that not all implementations support all algorithms. The Keycard applet implements P2 = 0x00 and, since 4.0, P2 = 0x03.

P1 must be 0x01: the key path is always taken from the data field. An empty path means the master key. Since 4.0 there is no "current key" on the card — see the version note below.

P2Data field
0x00 (ECDSA)hash (32) ‖ path
0x03 (Schnorr)hash (32) ‖ tweak (32) ‖ path

The hash can be produced by any algorithm, as long as it is 32 bytes long.

  • Tag 0xA0 = signature template
    • Tag 0x80 = ECC public key component
    • Tag 0x30 = ECDSA Signature
      • Tag 0x02 = R value
      • Tag 0x02 = S value

If calculating the recovery ID on card is too expensive the card is allowed to return the template above instead of a raw signature, in which case a client that needs the recovery ID can derive it by trying recovery IDs from 0 and checking which one recovers the public key returned in the template. Implementations that do return a recovery ID use:

  • Tag 0x80 = raw signature (65 bytes: r, s, recId)

A client must accept either format.

Introduced in 4.0, P2 = 0x03 produces a BIP-340 signature, as used by Bitcoin Taproot. The mandatory 32-byte tweak is added to the derived private key before signing, which is what makes Taproot key-path spending possible; pass 32 zero bytes for an untweaked key.

The signature is returned as:

  • Tag 0xA0 = signature template
    • Tag 0x80 = ECC public key component
    • Tag 0x88 = raw signature (64 bytes: 32-byte x-only public key, 32-byte signature)

The returned public key is the tweaked one, so it is the key the signature must be verified against.

Before 4.0, P1 could additionally be 0x00 (sign with the key left active by a previous DERIVE KEY), 0x02 (derive and make current) or 0x03 (sign with the pinless path, the one case where no secure channel and no PIN were needed). Those options are gone: DERIVE KEY no longer exists and neither does pinless signing, so 0x01 with an explicit path is the only form, and a secure channel plus PIN verification are always required.

Last edited
16 Oct 2026