EC Signature
Introduction To EC Signature
The EC Signature command enables you to generate digital signatures using Elliptic Curve Digital Signature Algorithm (ECDSA) with the secp256k1 curve. This functionality is essential for authenticating transactions, messages, or documents, ensuring their integrity and origin.
Key Features of the EC Signature Command:
- Key Pair Derivation:
- The key pair can be derived before signing, either relatively or absolutely.
- The card derives the key just before signing but does not change the currently stored key.
- Randomized Signatures:
- For ECDSA and Schnorr, the ephemeral 'k' value is randomly generated for each signature.
- In ECDSA, this randomness is handled automatically by the JCOP4 platform, ensuring high security.
- The applet does not use RFC6979 deterministic signatures.
- Blockchain Compatibility:
- The signature can be EOSIO-compatible when P2=1 is set in the sign command.
- To align with blockchain standards, the S value is always "canonical," ensuring it is in the lower range (S < n/2).
- The output format follows X9.62 ASN1 DER encoding, storing r and s values as integers. This is the standard raw format for many blockchains.
- Schnorr Signatures (BIP340 - Bitcoin):
- The card can sign 32-byte messages using the BIP340 Schnorr algorithm.
- A random 32-byte nonce is generated securely from the JCOP4 platform.
- The signature output is 64 bytes long (R|S), following the BIP340 standard.
- User Authentication & Pin N Reset:
- Signing resets pin or user key authentication, meaning a new pin verification is required before executing any commands that need authentication.
- If multiple hashes are authorized for signing, they must be signed in the exact order of authentication.
- The auth reset occurs after all (up to 4) authorized signatures have been completed.
For further details, refer to the Sign command specifications.
Command Specifications
Sign Command
The Sign command enables you to generate digital signatures using Elliptic Curve Digital Signature Algorithm (ECDSA) with the secp256k1 curve.
The following is the Python object for this command:
class SignCommand:
def __init__(self,
p1: int,
p2: int,
data: bytes,
pin: bytes = None,
derivation_path: bytes = None):
self.p1 = p1
self.p2 = p2
self.data = data
self.pin = pin
self.derivation_path = derivation_path
def to_dict(self):
return {
"p1": self.p1,
"p2": self.p2,
"data": self.data.hex(),
"pin": self.pin.hex() if self.pin else None,
"derivation_path": self.derivation_path.hex() if self.derivation_path else None
}
For example,
sign_command = SignCommand(
p1=0x01,
p2=0x02,
data=bytes.fromhex("aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899"),
pin=bytes.fromhex("31323334353637383900"), # "123456789" padded with 0x00
derivation_path=bytes.fromhex("8000002c8000003c80000000")
)
print(sign_command.to_dict())
Application Protocol Data Unit (APDU) Components
The following table outlines the components of the Application Protocol Data Unit (APDU).
Prerequisites:
- The secure channel must be open (except for pinless).
- User pin must be provided in data or a pinless key must be active (with the key use for signing in the pinless path).
- A valid keypair must be loaded .
Field | Description | Value |
---|---|---|
CLA | This field specifies the class of the instruction. | 0x80 |
INS | This field specifies the particular command or operation that the smart card or secure element should execute. | 0xC0 |
P1 | First parameter of the instruction that specifies the details about the operation being requested. | Key to use and derivation options. See the table below for more information. |
P2 | First parameter of the instruction that specifies additional details about the operation being requested. | Signature type (ECDSA, EOSIO canonical, Schnorr). See the table below for more information. |
Data | Key data | The hash to sign (32 bytes) Optionally: Path 32-bit integers list (whenP1 LSB = 1) |
The following table outlines the values for the P1 and P2 fields within the ADPU components based on some conditions:
Field | Field Value | Description |
---|---|---|
P1 (Key to use) | 0x00 | Current key k1 |
0x01 | Derive with k1 + derive flag for source | |
0x10 | Current key r1 | |
0x11 | Derive with r1 + derive flag for source | |
0x03 | Pinless path (k1 only) | |
P2 (Signature type) | 0x00 | ECDSA with canonical low S. |
0x01 | ECDSA with filter signature to fit EOSIO standard. | |
0x02 | Bitcoin Schnorr BIP340 signature, only with k1. |
Response
The following table outlines the possible responses that you will receive:
Response Code | Description |
---|---|
0x9000 | Success |
0x6A80 |
|
0x6A88 | P1 is set to 0x03 but the pinless path is not defined. |
0x6985 | No key loaded. |
0x63Cx | Incorrect pin. |
0x6700 | The data is shorter than expected with the pin. |
0x6B00 |
|
Response data | The response data consists of a public key and signature. |
Additional Information
Response Data Format
For ECDSA:
- The signature is returned in ASN.1 DER X9.62 format. The hash to be signed must be exactly 32 bytes long and can be generated using any algorithm. The output is a standard DER-formatted ECDSA signature.
- For some blockchains, an additional recovery ID is needed. To determine the recovery ID, you must follow the same process used for public key recovery in a transaction. Start with a recovery ID of 0 and check if the recovered public key matches the one provided in the template. If it matches, you have found the correct recovery ID. If not, increment the recovery ID and repeat the process until you find a match.
For BIP340 (P2=2)
- The signature output is 64 bytes long, consisting of R and S values (each 256 bits) in MSB-first order, following the BIP340 standard. This works only with k1 keys, whether they are the current key, a derived key, or a pinless key.
- P1 = 0x01 or 0x11 allows deriving a key using the path provided in the data field without changing the card's current path. The derivation source can be specified by OR'ing P1 with constants from the DERIVE KEY command (bits 7-6), allowing derivation from the master key, parent key, or current key.
- P1 = 0x03 is designed for payment transactions. It can be executed without a Secure Channel since no sensitive information is transmitted and does not require pin authentication. The card's current derivation path remains unchanged, but signing uses the PIN-less derivation path previously set with the SET PINLESS PATH command.
- In the sign command, the pin must always be exactly 9 digits long and right-padded with 0x00 if necessary.
Pin Requirement And Authentication Check
If there is no valid user authentication or the card is not in pinless mode, the pin must be included in the data provided for signing. In such cases, the expected data length includes the pin. When the pin is included, a pin attempt is counted each time this command is executed.
Pin Attempt Counting
A pin attempt is always counted when calling this command with a data field longer than 9 bytes, if there was no valid user authentication or the card was not in pinless mode. The card first checks if user authentication is valid for the signature operation. If it is a valid pinless case, it proceeds. Otherwise, it looks for the pin at the end of the data field.
User Authentication After A Successful Signature
Once a signature operation is completed successfully, user authentication remains active:
- If a pin was provided, it stays verified for other commands.
- If user key authentication was used, EC authentication remains valid for further commands, as if a challenge was signed (such as for a transaction hash).
Handling Incorrect Pin Attempts
If an incorrect pin is provided, pin authentication is disabled because a failed pin verification occurred.
Signing Multiple Hashes
When signing multiple hashes that were authorized by a key, they must be signed one by one in the exact order they were authorized. The pin is considered verified only after the last authorized hash has been signed.
Updated 4 months ago