Разработка системы верификации лекарственных препаратов на блокчейне
Фальсифицированные лекарства — это не абстрактная проблема. ВОЗ оценивает долю поддельных препаратов на рынках развивающихся стран в 10-30%. В Евросоюзе Директива 2011/62/EU (Falsified Medicines Directive) обязывает производителей размещать уникальный серийный номер и код верификации на каждой упаковке. Blockchain даёт конкретное преимущество над централизованными реестрами: производитель, дистрибьютор и аптека не доверяют друг другу — им нужен общий immutable ledger без единственного администратора.
Реальные внедрения: MediLedger (крупнейший фармацевтический consortium в США, Pfizer, Genentech, AmerisourceBergen), Track and Trace EU система, пилоты на Hyperledger Fabric в Индии и Китае. Архитектурные уроки из этих систем позволяют не изобретать велосипед.
Требования к данным и регуляторный контекст
Serialization данных на упаковке
Стандарт GS1 DataMatrix на фарм упаковке кодирует четыре атрибута (DSCSA в США, FMD в EU):
- GTIN (Global Trade Item Number) — идентификатор продукта
- Lot number — номер партии
- Expiry date — срок годности
- Serial number — уникальный для каждой упаковки
GS1 Application Identifiers:
(01)04150753537323 — GTIN
(17)270131 — Expiry (YYMMDD)
(10)LOT-A4581 — Lot number
(21)000123456789 — Serial number
DataMatrix scannable string:
]d201041507535373232702310100101-A45812100123456789
Серийный номер + GTIN = уникальный ключ для on-chain записи. Все остальные данные — атрибуты этого ключа.
Приватность данных: zero-knowledge или private channels
Критическая архитектурная проблема. Конкурирующие фармацевтические компании не хотят раскрывать объёмы продаж, логистические партнёры не раскрывают маршруты. On-chain данные публичны по умолчанию. Решения:
Hyperledger Fabric private data collections. Консорциумный blockchain с private channels: данные о конкретной транзакции видны только участникам канала, на публичном ledger хранится только hash. Это стандартное решение для корпоративных консорциумов (MediLedger использует этот подход).
ZK proofs для верификации. Аптека доказывает что препарат из легитимной цепочки поставок без раскрытия конкретного дистрибьютора:
// Verifier контракт: проверяет ZK proof легитимности
contract DrugVerifier {
IVerifier public zkVerifier; // Groth16 или PLONK verifier
// Merkle root всех легитимных серийных номеров (обновляется регулятором)
bytes32 public legitimacyRoot;
// Аптека: доказать что S/N в легитимном дереве без раскрытия S/N
function verifyDrug(
bytes calldata proof,
uint256[2] calldata publicInputs // [nullifier, merkle_root]
) external view returns (bool) {
// publicInputs[0] — nullifier (не повторить верификацию той же упаковки)
// publicInputs[1] — должен совпадать с legitimacyRoot
require(publicInputs[1] == uint256(legitimacyRoot), "Wrong root");
return zkVerifier.verifyProof(proof, publicInputs);
}
}
Chain of custody: трансфер владения
Каждое перемещение упаковки — событие transfer custody. Производитель → дистрибьютор → аптека → пациент. Каждый шаг должен быть верифицирован обеими сторонами (передающей и принимающей).
contract DrugTraceability {
enum Status { MANUFACTURED, IN_TRANSIT, RECEIVED, DISPENSED, RECALLED }
struct DrugUnit {
bytes32 serialHash; // keccak256(GTIN + serial) — не храним в открытую
address currentHolder;
Status status;
uint256 manufacturedAt;
uint256 expiryTimestamp;
bool recalled;
}
mapping(bytes32 => DrugUnit) public drugs; // serialHash => DrugUnit
mapping(bytes32 => address[]) public custodyHistory;
// Производитель регистрирует упаковку
function manufacture(
bytes32 serialHash,
uint256 expiryTimestamp,
bytes32 lotMerkleRoot // Merkle root для верификации lot атрибутов
) external onlyManufacturer {
require(drugs[serialHash].manufacturedAt == 0, "Already registered");
drugs[serialHash] = DrugUnit({
serialHash: serialHash,
currentHolder: msg.sender,
status: Status.MANUFACTURED,
manufacturedAt: block.timestamp,
expiryTimestamp: expiryTimestamp,
recalled: false
});
custodyHistory[serialHash].push(msg.sender);
emit Manufactured(serialHash, msg.sender, block.timestamp);
}
// Двухсторонний трансфер: инициирует отправитель, подтверждает получатель
mapping(bytes32 => address) public pendingTransfer; // serialHash => proposed recipient
function initiateTransfer(bytes32 serialHash, address recipient) external {
require(drugs[serialHash].currentHolder == msg.sender, "Not holder");
pendingTransfer[serialHash] = recipient;
emit TransferInitiated(serialHash, msg.sender, recipient);
}
function confirmTransfer(bytes32 serialHash) external {
require(pendingTransfer[serialHash] == msg.sender, "Not recipient");
drugs[serialHash].currentHolder = msg.sender;
custodyHistory[serialHash].push(msg.sender);
delete pendingTransfer[serialHash];
emit TransferConfirmed(serialHash, msg.sender);
}
// Отзыв препарата (recall)
function recall(bytes32 serialHash, string calldata reason) external onlyRegulator {
drugs[serialHash].recalled = true;
emit Recalled(serialHash, reason, block.timestamp);
}
}
Интеграция с физическим миром
Tamper-evident packaging + NFC/QR
Blockchain полезен только если связь между физической упаковкой и on-chain записью надёжна. Три уровня защиты:
QR код с DataMatrix — минимум, соответствующий FMD. Уязвимость: QR можно скопировать и наклеить на поддельный препарат. Помогает от грубых подделок, но не от sophisticated атак.
NFC с криптографическим challenge-response (например, NXP NTAG 424 DNA). Чип содержит private key в защищённой памяти (не извлекаем). При сканировании генерирует подписанный challenge — невозможно клонировать без физического доступа к чипу. Производитель при выпуске регистрирует public key чипа on-chain.
// Верификация NFC чипа (reader side)
async function verifyNFCChip(
chipPublicKey: string,
challenge: Buffer,
signature: Buffer
): Promise<boolean> {
// Верифицируем подпись чипа
const isValidSignature = await verifyECDSA(chipPublicKey, challenge, signature)
// Проверяем регистрацию публичного ключа on-chain
const isRegistered = await contract.isChipRegistered(chipPublicKey)
// Проверяем что чип не в списке recalled
const isRecalled = await contract.isRecalled(chipPublicKey)
return isValidSignature && isRegistered && !isRecalled
}
Holographic labels + blockchain — гибридный подход для рынков без NFC инфраструктуры.
Off-chain данные и IPFS
Полная документация партии (Certificate of Analysis, результаты тестирования) не помещается в blockchain. Стандартный паттерн:
- On-chain:
bytes32 documentsIPFSHash— Merkle root или IPFS CID документов - Off-chain: IPFS хранит документы
- Верификатор: получает документы через IPFS, проверяет hash on-chain
struct BatchRecord {
bytes32 lotNumber;
address manufacturer;
uint256 productionDate;
bytes32 coaIpfsHash; // Certificate of Analysis
bytes32 testResultsHash; // Результаты QC тестирования
uint32 quantity;
}
Выбор блокчейна для фармацевтики
| Параметр | Публичный (Ethereum/Polygon) | Permissioned (Hyperledger Fabric) |
|---|---|---|
| Доступность данных | Публичный, все видят | Private channels |
| Участники | Любые кошельки | KYC'd участники консорциума |
| Стоимость транзакций | Gas (оптимизировать) | Практически бесплатно |
| Regulatory compliance | Сложнее (публичность) | Проще |
| Decentralization | Высокая | Консорциум |
| Скорость | L2: ~2 сек | ~1 сек |
Рекомендация: для B2B консорциума производителей/дистрибьюторов — Hyperledger Fabric (MediLedger модель). Для consumer-facing верификации (пациент проверяет препарат) — публичный blockchain (Polygon или Arbitrum для стоимости газа) с privacy-preserving ZK проверкой.
Hyperledger Fabric: ключевые концепции
// Chaincode (смарт-контракт) на Go
package main
import (
"github.com/hyperledger/fabric-contract-api-go/contractapi"
)
type DrugContract struct {
contractapi.Contract
}
func (c *DrugContract) RegisterDrug(ctx contractapi.TransactionContextInterface,
serialHash, gtin, lot, expiry string) error {
// Проверить что вызывает авторизованный производитель
mspID, _ := ctx.GetClientIdentity().GetMSPID()
if !isAuthorizedManufacturer(mspID) {
return fmt.Errorf("unauthorized: %s", mspID)
}
// Проверить дубликат
existing, _ := ctx.GetStub().GetState(serialHash)
if existing != nil {
return fmt.Errorf("drug %s already registered", serialHash)
}
drug := Drug{
SerialHash: serialHash,
GTIN: gtin,
Lot: lot,
Expiry: expiry,
Holder: mspID,
Status: "MANUFACTURED",
Timestamp: time.Now().Unix(),
}
drugJSON, _ := json.Marshal(drug)
return ctx.GetStub().PutState(serialHash, drugJSON)
}
Регуляторные интерфейсы
Регулятор (FDA, EMA, локальный орган) должен иметь доступ на чтение и право recall. В Hyperledger Fabric: отдельный channel между производителями и регулятором. В публичном blockchain: on-chain role через AccessControl.
// OpenZeppelin AccessControl для ролей
bytes32 public constant MANUFACTURER_ROLE = keccak256("MANUFACTURER_ROLE");
bytes32 public constant DISTRIBUTOR_ROLE = keccak256("DISTRIBUTOR_ROLE");
bytes32 public constant REGULATOR_ROLE = keccak256("REGULATOR_ROLE");
// Только регулятор может отозвать
function recall(bytes32 serialHash, string calldata reason)
external onlyRole(REGULATOR_ROLE) { ... }
Процесс разработки
Регуляторный анализ (1-2 недели). Определяем применимые стандарты: DSCSA (США), FMD (EU), локальные требования. Фармацевтические системы подпадают под требования к validated software (FDA 21 CFR Part 11) — нужна документация и trace матрица требований.
Архитектурный дизайн (1-2 недели). Выбор blockchain (permissioned vs public), privacy модель, схема данных GS1, NFC/QR стратегия. Проектируем схему участников консорциума и governance.
Smart contract разработка (4-6 недель). Контракты регистрации, custody transfer, recall. Расширенное тестирование: edge cases (упаковка после recall, expired drug transfer, duplicate serial numbers).
Backend интеграция (4-8 недель). API для интеграции с ERP системами производителей (SAP, Oracle Pharma), WMS дистрибьюторов. Batch import для регистрации тысяч серийных номеров одновременно.
Hardware интеграция (2-4 недели). SDK для сканеров DataMatrix, NFC readers, интеграция с существующим складским оборудованием. Offline mode для слабосвязанных сетей (аптеки в удалённых регионах).
Аудит и валидация (4-6 недель). Smart contract аудит (обязательно — данные о лекарствах влияют на здоровье людей). Validation documentation для регуляторного compliance (IQ/OQ/PQ по GAMP5).
Ориентиры по срокам
MVP для pilot с одним производителем и одной аптечной сетью — 3-4 месяца. Production система для consortium с full регуляторным compliance — 9-15 месяцев. Сложность проекта определяется не blockchain частью, а интеграцией с legacy ERP систем участников и регуляторной валидацией.







