Hello NXP Community,
I am implementing the ICODE SLIX2 originality signature verification described
in AN11350 on an embedded MCU (GD32F303CC, ARM Cortex-M4) using an RC663
ISO 15693 reader. The signature is successfully read from the tag (32 bytes via
command 0xBD), but ECDSA verification always fails.
I would greatly appreciate clarification on the correct hash/message format.
────────────────
Hardware & Software
────────────────
Reader: NXP RC663
Tag: NXP ICODE SLIX2 (SL2S2602)
Curve: secp128r1 (confirmed by 32-byte signature = r||s, 16 bytes each)
ECC library: easy-ecc (https://github.com/jestan/easy-ecc)
compiled with ECC_CURVE = secp128r1 (ECC_BYTES = 16)
MCU: GD32F303CC (ARM Cortex-M4, no OS)
───────────────
READ_SIGNATURE Command (0xBD)
──────────────
Request frame (11 bytes, ISO 15693 addressed mode):
FLAGS = 0x22 (High Data Rate | Address flag)
CMD = 0xBD (READ_SIGNATURE, NXP custom command)
MFG_CODE = 0x04 (NXP IC manufacturer code — required for 0xA0–0xDF range)
UID = 8 bytes (addressed)
Response (33 bytes):
FLAGS = 0x00 (no error)
SIG = 32 bytes
The 32-byte signature and the UID are confirmed correct by comparing with
a proxmark3 scan of the same tag.
──────────────────
Public Key
──────────────────
33bytes pubic key:048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0
Using the secp128r1 compressed public key (17 bytes):
0x02, 0x88, 0x78, 0xA2, 0xA2, 0xD3, 0xEE, 0xC3, 0x36, 0xB4, 0xF2, 0x61, 0xA0, 0x82, 0xBD, 0x71
(prefix = 0x02 because the y-coordinate's LSB is odd)
The public key has been confirmed correct by the tag vendor.
────────────────────
UID Byte Order in RC663 Buffer
────────────────────
ISO 15693 transmits the UID LSB-first. RC663 fills the receive buffer in
reception order, so:
UID[0] = first byte received = LSB of the 64-bit UID
UID[7] = last byte received = 0xE0 (MSB, fixed ISO 15693 prefix)
Example tag UID (display/big-endian order): E0 04 01 A2 B3 C4 D5 E6
Buffer contents: UID[] = { E6, D5, C4, B3, A2, 01, 04, E0 }
───────────────────
My Question: What Is the Correct Hash/Message Format?
───────────────────
AN11350 states the signature is computed over the UID, but does not clearly
specify:
1. The byte order of the UID used as the ECDSA message
(big-endian display order vs. the LSB-first order received from the tag)
2. How the 8-byte UID is zero-padded to fill the full 128-bit hash field
I have tried all four plausible combinations below — all return verification
failure:
Option A: UID raw (LSB-first) in high 8 bytes of hash, zeros in low 8 bytes
hash = { UID[0], UID[1], ..., UID[7], 0, 0, 0, 0, 0, 0, 0, 0 }
Option B: UID reversed (big-endian) in high 8 bytes, zeros in low 8 bytes
hash = { UID[7], UID[6], ..., UID[0], 0, 0, 0, 0, 0, 0, 0, 0 }
Option C: zeros in high 8 bytes, UID raw (LSB-first) in low 8 bytes
hash = { 0, 0, 0, 0, 0, 0, 0, 0, UID[0], UID[1], ..., UID[7] }
Option
hash = { 0, 0, 0, 0, 0, 0, 0, 0, UID[7], UID[6], ..., UID[0] }
In easy-ecc, ecc_bytes2native() treats the 16-byte hash buffer as a big-endian
128-bit integer:
p_native[1] (high 64-bit word) ← hash[0..7]
p_native[0] (low 64-bit word) ← hash[8..15]
────────────────────
Verification Code (simplified)
────────────────────
int ok = ecdsa_verify(nxp_pubkey, hash, sig); /* 0 = fail, 1 = pass */
────────────────────