NFC Chip to NFT Binding Development
Physical objects and NFTs — obvious concept, poor implementation makes the whole project pointless. If binding reduces to "scan chip — opens OpenSea link," NFT here is decorative. Real connection means the physical object can't be duplicated without cryptographic forgery. Solvable — but only if chip can sign messages with private key embedded and unextractable.
Chip Selection: Cryptography Requirements
Not every NFC chip fits. NTAG213/215/216 — standard Mifare tags for simple URL reading. Zero cryptography, cloned in 10 seconds with any Android + NFC Tools Pro.
Need chip with asymmetric key pair and signing capability:
NXP NTAG 424 DNA — most common choice. AES-128 onboard, SUN (Secure Unique NFC) message authentication. On each read generates unique CMAC-signed message with rolling counter. Private key written at production and never readable externally. Cost — $1-3 per chip in batch.
Kong Halo — designed specifically for phygital NFT. ECC (secp256k1 — same curve as Ethereum), each read generates ECDSA signature over keccak256(chipAddress || blockHash || counter). Compatible with EIP-191 personal_sign, signature verification on-chain via ecrecover. Native integration with ERS (Ethereum Registrar Standards) protocol.
Arx Research HaLo — analogous to Kong Halo. Used in RTFKT, Adidas Physical NFT projects. Chip public key — deterministic Ethereum address.
For serious phygital project, choice between NTAG 424 DNA and HaLo depends on task: NTAG 424 cheaper and more standard, HaLo natively compatible with Ethereum signatures and requires no custom verification.
Cryptographic Binding Scheme
HaLo / Kong Halo Scheme
Each chip has embedded secp256k1 keypair. Public key — chipAddress. On read via phone (Web NFC API or native app), chip signs challenge:
signature = ECDSA.sign(
privateKey,
keccak256(abi.encodePacked(chipAddress, cmdBlock, counter))
)
counter increments on each read — replay attack impossible. cmdBlock contains specific command data.
Smart contract stores chipAddress => tokenId mapping. Ownership verification:
function verifyChipSignature(
uint256 tokenId,
bytes calldata signatureFromChip,
bytes32 blockHash,
uint256 blockNumber
) external view returns (bool) {
require(block.number - blockNumber <= MAX_BLOCK_AGE, "Stale");
address chipAddress = chipAddressOf[tokenId];
bytes32 digest = keccak256(abi.encodePacked(
chipAddress,
blockHash
));
address recovered = ECDSA.recover(digest, signatureFromChip);
return recovered == chipAddress;
}
blockHash included in signature to bind scan to specific moment in time — protection against saved and replayed signatures.
NTAG 424 DNA Scheme
Chip uses AES-128 CMAC. Each read generates URL like:
https://verify.project.xyz/?e=<encrypted_uid>&c=<cmac>
encrypted_uid — AES-128 encrypted chip UID (unique), cmac — Message Authentication Code, includes rolling counter. Verification server decrypts UID and checks CMAC with known secret key. Counter checked for monotonic increase.
Weakness vs HaLo: AES key must be known to verification server. Server compromise = ability to clone signatures. For HaLo private key knows no one.
Contract Binding: PBT Standard
EIP-5791 (Physical Backed Token) — standard for exactly this. Extends ERC-721 with two functions:
function tokenIdMappedFor(address chipAddress) external view returns (uint256);
function isChipSignatureForToken(uint256 tokenId, bytes calldata payload, bytes calldata signature) external view returns (bool);
Reference implementation — Chiru Labs PBT. Inherit from PBT, override verification logic for specific chip.
Token transfer via chip scan — transferTokenWithChip():
function transferTokenWithChip(
bytes calldata signatureFromChip,
uint256 blockNumberUsedInSig
) external {
require(block.number - blockNumberUsedInSig <= getMaxBlockhashValidWindow(), "Expired");
bytes32 blockHash = blockhash(blockNumberUsedInSig);
require(blockHash != bytes32(0), "Block too old");
bytes32 digest = keccak256(abi.encodePacked(msg.sender, blockHash));
address chipAddress = digest.recover(signatureFromChip);
uint256 tokenId = _chipAddressToTokenId[chipAddress];
_transfer(ownerOf(tokenId), msg.sender, tokenId);
}
Means: to transfer NFT to new wallet, must physically hold object to phone and sign transaction simultaneously. Without physical object — transfer impossible. This is key property for luxury goods and collectibles.
Mobile App and Web NFC
Reading HaLo chips:
- Web NFC API (Chrome Android): works without app, Android only
- iOS: requires native app (NFC entitlement Apple)
- React Native + react-native-nfc-manager: cross-platform option
Example scan via Web NFC:
const ndef = new NDEFReader();
await ndef.scan();
ndef.addEventListener("reading", ({ message }) => {
const record = message.records[0];
const decoder = new TextDecoder();
const url = decoder.decode(record.data);
// Parse params, call verification
handleChipScan(url);
});
For HaLo need their JavaScript SDK (@arx-research/libhalo) — abstracts low-level APDU command work.
Production and Firmware
Chips programmed batch-script: generate key pairs (if chip allows custom keys) or record public keys from factory pairs in database. Each chip mapped to chipAddress.
On collection NFT mint: frontend gets chipAddress → tokenId list and calls setChipAddresses(tokenId[], chipAddress[]) in contract. Or chips programmed with already-known tokenIds and contract verifies mapping on first scan.
Protection from chip swap at production: chip laminated or sealed into item so physical removal destroys good. Stickers with chips vulnerable to moving — don't suit expensive goods.
Applications and Scenarios
Luxury goods: sneakers, watches, bags — chip scan confirms authenticity and ownership history. Resale market sees full provenance.
Ticketing + physical collectible: concert ticket with NFC = NFT + physical stub. After event NFT remains as proof of attendance, chip scan at entry = on-chain check-in.
Game figures / trading cards: scan figure mints game item in metaverse. Sell physical figure = transfer NFT via chip signature.
Art: artist deploys 1/1 NFT with chip in frame. Buying painting = transfer via chip scan. Can't sell NFT without physical work transfer.







