Разработка системы верификации подлинности через NFT
Физический товар с QR-кодом «подтверждённым блокчейном» — это маркетинг, не безопасность. Настоящая проблема в том, что NFT хранит ссылку на что-то, но не само это что-то. Подделать физический предмет и переклеить QR-код с оригинального на копию — тривиально, если система не решает задачу криптографической привязки физического объекта к цифровому токену. Это то, что нужно проектировать в первую очередь.
Привязка физического объекта к NFT
NFC-чипы с криптографией
Самый надёжный подход для физических товаров — NFC-чипы с поддержкой ECC подписей (NTAG 424 DNA от NXP или аналоги Kong Halo). Чип содержит приватный ключ, который не может быть извлечён из устройства физически. При сканировании чип подписывает challenge-ответ приватным ключом.
Схема верификации:
- При производстве товара чип генерирует keypair. Публичный ключ записывается в NFT метаданные и в контракт верификации.
- Для верификации пользователь сканирует NFC → чип подписывает
keccak256(randomChallenge || timestamp)→ подпись отправляется в backend или прямо в контракт. - Контракт проверяет подпись через
ecrecover— еслиrecovered_address == chip_public_keyиchip_public_keyзарегистрирован как принадлежащий конкретному tokenId — товар подлинный.
function verifyChip(
uint256 tokenId,
bytes32 challenge,
bytes memory signature
) external view returns (bool) {
address chipAddress = _chipAddresses[tokenId];
require(chipAddress != address(0), "Token not registered");
bytes32 messageHash = keccak256(
abi.encodePacked("\x19Ethereum Signed Message:\n32", challenge)
);
address recovered = ECDSA.recover(messageHash, signature);
return recovered == chipAddress;
}
Протокол Kong (ERC-7015 / Kong Halo) стандартизирует именно эту схему. Для люксовых товаров, часов, кроссовок — это production-ready решение.
QR-код без физической криптографии
Если NFC не подходит (бумажные документы, упаковка), используется другая схема. Производитель создаёт пару (publicId, secretKey) — publicId вшивается в QR-код и хранится в NFT, secretKey печатается внутри упаковки под защитным слоем. При проверке пользователь вскрывает упаковку, вводит secretKey — backend проверяет что keccak256(secretKey) == storedHash.
Это одноразовая схема: после первой проверки секрет раскрыт. Для повторных верификаций нужен другой механизм. Подходит для предметов коллекционирования, алкоголя, фармацевтики.
On-chain реестр подлинности
Структура контракта
Реестр хранит маппинг tokenId → AuthRecord:
struct AuthRecord {
address chipAddress; // публичный ключ NFC чипа или нулевой адрес
bytes32 secretHash; // keccak256 от secret для QR схемы
uint256 mintedAt; // timestamp создания
uint256 verificationCount; // сколько раз верифицировали
bool activated; // активирован ли (для одноразовых)
string productSku; // SKU производителя
}
mapping(uint256 => AuthRecord) private _authRecords;
verificationCount — полезная аналитика. Товар, которого верифицировали 500 раз — либо очень популярный, либо кто-то пытается брутфорсить. Threshold alert на backend при аномальном количестве верификаций.
Статусы жизненного цикла
Для более сложных сценариев добавляется статус:
| Статус | Описание |
|---|---|
MINTED |
Токен создан, товар не активирован |
ACTIVATED |
Товар вскрыт/активирован первым владельцем |
TRANSFERRED |
Токен передан, история передач сохранена |
FLAGGED |
Помечен как возможная подделка |
BURNED |
Товар уничтожен или утилизирован |
История передач прозрачна через стандартные ERC-721 Transfer events — не нужно хранить отдельно.
Верификация без on-chain транзакции
Верификация не должна требовать gas от пользователя — это барьер для adoption. Два подхода:
Off-chain с on-chain доказательством. Backend делает eth_call к контракту верификации (бесплатно), результат возвращает пользователю. Источник истины — блокчейн, но gas не платится.
Gasless верификация через signature. Пользователь подписывает запрос верификации (EIP-712), backend проверяет подпись чипа и подпись пользователя, записывает событие верификации в off-chain лог (с cryptographic proof). Для критичных верификаций (страховые, юридические) — периодическая on-chain запись Merkle root от batch верификаций.
Интеграция с маркетплейсами
Стандарт ERC-721 + дополнительные метаданные. В tokenURI JSON добавляются поля:
{
"name": "Product #12345",
"attributes": [
{"trait_type": "Authenticity", "value": "Verified"},
{"trait_type": "Manufacturer", "value": "Brand XYZ"},
{"trait_type": "SKU", "value": "PROD-2024-001"},
{"trait_type": "Chip Type", "value": "NXP NTAG 424 DNA"}
],
"verification_contract": "0x...",
"chip_public_key": "0x..."
}
OpenSea и другие маркетплейсы отображают эти атрибуты. Покупатель на вторичном рынке может верифицировать товар перед покупкой.
Роли и права доступа
Контракт использует OpenZeppelin AccessControl:
-
MANUFACTURER_ROLE— право минтить новые токены и регистрировать чипы -
VERIFIER_ROLE— право записывать результаты верификации on-chain (для enterprise клиентов) -
FLAGGING_ROLE— право помечать токены как спорные (антиподдельная служба бренда) -
DEFAULT_ADMIN_ROLE— управление ролями
Производитель может делегировать авторизованным дистрибьюторам право регистрировать продукты в своём сегменте.
Стек разработки
Solidity 0.8.20+ + Foundry + OpenZeppelin 5.x. ERC-721 + кастомный верификационный контракт. Backend: Node.js + TypeScript + viem, API для mobile верификации. Mobile SDK: React Native или Flutter для сканирования NFC/QR. Деплой: Polygon или Base (низкий gas для частых операций минтинга).
Ориентиры по срокам
Система с QR-кодами и on-chain реестром без NFC — 1 неделя. С поддержкой NFC-чипов (Kong/NTAG 424 DNA), ролевой моделью, mobile SDK для сканирования и аналитическим dashboard — 2-3 недели.







