Skip to main content

3. Card Storage Model

Zones

  • Active Buffer: Primary state storage. Identified by activePtr in the trailer.
  • Shadow Buffer: Secondary state for atomic A/B writes. Becomes the new active buffer after a successful write and pointer flip.
  • Trailer / Meta: Metadata, HMAC, and active buffer pointer. Occupies the last 64 bytes of the usable NFC memory.

Target size: 496 bytes on NTAG215.

For NTAG215, each active or shadow buffer must fit inside roughly 216 bytes, with the trailer occupying the remaining 64 bytes.

Encoding conventions

  • All multi-byte integer fields are little-endian unless noted otherwise.
  • Timestamps are UTC seconds stored as uint32 (seconds since Unix epoch).
  • String fields (name) are UTF-8, null-padded to fill the fixed allocation.
  • balance and lastBalance are stored in the smallest currency unit (e.g., integer Rupiah, no decimals).
  • Reserved fields must be zeroed on write and ignored on read.

Payload fields

The active and shadow buffers each have a fixed size of 216 bytes on NTAG215. The trailer/meta block is separate and occupies 64 bytes.

Header / Identifier Block (16 bytes)

FieldSizeTypeDescription
magic4 BbytesFixed 4-byte magic value for payload identification
version1 Buint8Card layout schema version
type1 Buint8Payload type or product class identifier
cardId6 BbytesUnique card identifier, set at issuance
reserved4 BReserved for future header fields (e.g. sub-type flags, extended version byte). Must be zeroed on write; ignored on read. Preserves 4-byte alignment of the block.

Identity Block (48 bytes)

FieldSizeTypeDescription
name32 BUTF-8Cardholder display name, null-padded
userId4 Buint32Internal user identifier
gender1 Buint8Gender code (application-defined)
status1 Buint8Card status code (see §15)
createdAt4 Buint32Card issuance timestamp (UTC seconds)
reserved6 BReserved to pad the Identity Block to a multiple of 4 bytes and to allow future fields (e.g. nationality code, extended user metadata). Must be zeroed on write; ignored on read.
FieldSizeTypeDescription
balance4 Buint32Current balance in smallest currency unit
lastBalance4 Buint32Balance before the most recent transaction; used for rollback detection
counter8 Buint64Monotonically increasing write counter; never decremented
lastTimestamp4 Buint32Timestamp of the most recent write (UTC seconds)
state1 Buint8Card lifecycle state (see §6)
flags3 BbitsFeature and operational flags

Session Block (16 bytes)

FieldSizeTypeDescription
startTime4 Buint32Session open timestamp (UTC seconds)
endTime4 Buint32Session close timestamp; zero if session is open
terminalId2 Buint16Identifier of the terminal that opened the session
reserved6 BPads the Session Block to 16 bytes for alignment. Reserved for future session fields (e.g. gateId that performed check-in, session type flag). Must be zeroed on write; ignored on read.

Logs (112 bytes — 7 entries × 16 bytes each)

See §14 for full log entry definition and chain integrity rules.

FieldSizeTypeDescription
deltaTime2 Buint16Seconds elapsed since session start
amount3 Buint24Transaction amount in smallest currency unit
balanceAfter4 Buint32Balance after this transaction
flags/type1 Buint8Transaction type and operational flags
hash6 BbytesTruncated SHA-256 chain hash

Capacity: 7 entries on NTAG215 (stored as a ring buffer).

Trailer / Meta (64 bytes)

FieldSizeTypeDescription
expiresAt4 Buint32Card expiry timestamp (UTC seconds)
keyVersion1 Buint8Version of the key set used to encrypt and authenticate this card
rootHash6 BbytesTruncated SHA-256 over the full log chain; anchors log sequence to current state
counterBind4 Buint32Lower 32 bits of counter included in HMAC input for replay resistance
reserved9 BReserved; zero on write
HMAC8 BbytesTruncated HMAC-SHA256 over payload and trailer fields
activePtr1 Buint80 = buffer A is active; 1 = buffer B is active
paddingremZero-padded to fill 64 bytes

Size summary

RegionSize
Header16 B
Identity48 B
Wallet + Runtime24 B
Session16 B
Logs112 B
Buffer total216 B
Trailer / Meta64 B
Total (2× buffer + trailer)496 B