260611_FBR_offline_VC

вот, ко мне приходит человек, и говорит что он принёс VC от моей мамы: "это — г-н Милейшев, дай ему 1000 рублей" я смотрю — издатель моя мама, подпись тоже её. А как я узнаю, что передо мной именно Милейшев, если он показывает просто ДИД номер и не может его подписать? (подтвердить) ... когда я отдаю Милейшеву 1000 руб Он должен подтвердить, что получил их, после этого VC становится деактивированным по причине его исполнения.

Да — Это двухсторонний протокол, где отзыв VC происходит не по инициативе издателя, а по факту исполнения обязательства. Давай разберем этот сценарий правильно.


🧠 Правильный сценарий "Исполнение VC"

Участники

Роль

Кто

Действие

Издатель (Issuer)

Мама

Выпускает VC "дать 1000 рублей Милейшеву"

Холдер (Holder)

Милейшев

Предъявляет VC и получает деньги

Верификатор (Verifier)

Ты

Даёшь деньги и подтверждаешь исполнение

Реестр статусов

HLF

Хранит состояние VC


🔄 Полный протокол с исполнением

Шаг 1. Мама выпускает VC

{ "id": "vc-mama-2024-001", "issuer": "did:mama", "credentialSubject": { "id": "did:example:mileyshev", "action": "дать 1000 рублей", "description": "за хорошую работу" }, "credentialStatus": { "id": "https://registry.example.com/status/vc-mama-2024-001", "type": "StatusList2021" }, "proof": { ... } // подпись мамы }

Шаг 2. Милейшев приходит к тебе

  1. Милейшев предъявляет VP (VC + свою подпись challenge).

  2. Ты проверяешь:

    • Подпись мамы в VC → валидно.

    • Подпись Милейшева в VP → валидно.

    • Статус VC в реестре → ACTIVE.

Шаг 3. Ты даёшь деньги и инициируешь "исполнение"

Ты передаёшь Милейшеву 1000 рублей и одновременно отправляешь запрос в реестр статусов:

POST https://registry.example.com/status/vc-mama-2024-001 { "status": "EXECUTED", "executedBy": "did:you", // твой DID "executedAt": "2026-07-11T14:30:00Z", "executionProof": { "type": "Ed25519Signature2020", "verificationMethod": "did:you#key-1", "proofValue": "z4JX..." // твоя подпись }, "recipientConfirmation": { "type": "Ed25519Signature2020", "verificationMethod": "did:example:mileyshev#key-1", "proofValue": "z7Kq..." // подпись Милейшева о получении } }

Важно: Запрос должен быть подписан двумя сторонами:

  • Ты (верификатор) — подтверждаешь, что передал деньги.

  • Милейшев (холдер) — подтверждает, что получил деньги.

Шаг 4. Реестр обновляет статус

HLF записывает новую запись:

credentialId: vc-mama-2024-001 status: EXECUTED executedAt: 2026-07-11T14:30:00Z executedBy: did:you recipient: did:example:mileyshev

Шаг 5. Милейшев пытается получить деньги у твоего брата

  1. Милейшев показывает тот же VC брату.

  2. Брат проверяет статус в реестре → видит EXECUTED.

  3. Брат говорит: "Извини, этот VC уже исполнен. Я не дам тебе денег."


🧩 Ключевые элементы этого протокола

1. Двусторонняя подпись исполнения

Кто подписывает

Что подтверждает

Ты (верификатор)

"Я передал 1000 рублей Милейшеву"

Милейшев (холдер)

"Я получил 1000 рублей от тебя"

Это защищает обе стороны:

  • Ты не можешь сказать "я не давал денег" — есть твоя подпись.

  • Милейшев не может сказать "мне не дали денег" — есть его подпись.

2. Новые статусы VC

Статус

Когда используется

Кто может изменить

ISSUED

Мама выпустила VC

—

ACTIVE

VC действителен (по умолчанию)

—

EXECUTED

Обязательство выполнено

Верификатор + Холдер (двусторонняя подпись)

REVOKED

Мама отозвала VC

Мама (односторонняя подпись)

EXPIRED

Истёк срок действия

Автоматически

3. Как предотвратить повторное использование

  • Реестр статусов хранит историю изменений статуса.

  • Верификатор всегда проверяет текущий статус.

  • После EXECUTED перевести обратно в ACTIVE невозможно (это транзакция в HLF).


🏗️ Реализация в вашем прототипе

API для исполнения VC

POST /vc/execute { "credentialId": "vc-mama-2024-001", "verifier": "did:you", "holder": "did:example:mileyshev", "verifierSignature": "z4JX...", "holderSignature": "z7Kq..." }

Логика VcSvc

  1. Проверить, что статус VC — ACTIVE.

  2. Проверить подпись верификатора (через DidSvc).

  3. Проверить подпись холдера (через DidSvc).

  4. Обновить статус в HLF на EXECUTED.

  5. Вернуть успех.

Логика верификатора (брат)

  1. Получить VP от Милейшева.

  2. Проверить подпись мамы в VC.

  3. Проверить подпись Милейшева в VP.

  4. Запросить статус VC в реестре.

  5. Если статус EXECUTED → отказ.


📌 Резюме

Твой вопрос

Ответ

Когда Милейшев подтверждает получение?

В момент получения денег он подписывает executionProof вместе с тобой.

Как VC становится исполненным?

Через двустороннюю транзакцию в реестре статусов (твоя подпись + подпись Милейшева).

Как брат узнает, что VC исполнен?

Он проверяет статус в реестре и видит EXECUTED.

Кто может изменить статус на EXECUTED?

Только ты + Милейшев (обе стороны должны подписать). Никто другой.

Короткий ответ:
VC исполняется через двустороннюю подпись в реестре статусов: ты подписываешь факт передачи денег, Милейшев — факт их получения. После этого статус меняется на EXECUTED, и никто не сможет использовать этот VC повторно.


*"Милейшев приходит к брату → брат видит в VP Акт исполнения" Милейшев может сделать копию VC и показать брату без моего Акта

затем он идет к третьему брату и показывает очередную копию...*

Ты абсолютно прав. Это клонирование VC — фундаментальная проблема всех цифровых данных.

Если Милейшев получает цифровую копию VC от мамы, он может бесконечно размножать её и показывать разным верификаторам без Акта исполнения. Ты даёшь деньги → подписываешь Акт → он кладёт его в карман. А следующему брату он просто не покажет этот Акт.


🔥 Проблема: офлайн-режим без реестра не решаема

В онлайне есть реестр статусов (HLF). Когда ты подписываешь Акт, он немедленно публикуется в реестре. Все верификаторы (братья) видят один и тот же реестр и знают, что VC исполнен.

В офлайне:

  • У тебя есть только локальный реестр (твоя копия Актов).

  • У брата есть свой локальный реестр.

  • Они не синхронизированы. Милейшев может использовать разные копии VC для разных братьев, пока не произойдёт синхронизация.

Вывод: Без общего реестра (даже слабо-онлайн) невозможно гарантировать, что VC был использован только один раз.


💡 Единственное техническое решение: Физический носитель с защитой от копирования

Чтобы офлайн-режим был безопасен, нужен аппаратный защищённый носитель (токен, смарт-карта), который:

  1. Хранит приватный ключ Милейшева.

  2. Не позволяет скопировать приватный ключ.

  3. Ведёт счётчик использований внутри себя.

Как это работает

Шаг

Действие

Где происходит

1.

Мама выпускает VC и записывает его на токен Милейшева.

Токен (смарт-карта)

2.

Милейшев приходит к тебе.

—

3.

Ты даёшь деньги.

—

4.

Ты подписываешь Акт (своим приватным ключом).

Твой токен

5.

Милейшев должен подписать Акт (своим приватным ключом).

Его токен

6.

Токен Милейшева увеличивает счётчик использований.

Внутри токена

7.

Милейшев идёт к брату.

—

8.

Брат запрашивает VC и счётчик у токена Милейшева.

Токен выдаёт VC + счётчик (подписанный самим токеном)

9.

Брат видит counter = 1 → отказ.

—


🧩 Техническая реализация (прототип)

Вариант 1. Эмуляция токена через мобильное приложение (сильная изоляция)

  • Приложение хранит приватный ключ в защищённом хранилище (Keychain/Keystore).

  • Приложение не даёт экспортировать ключ.

  • Приложение ведёт счётчик использований в защищённом хранилище.

  • Каждый раз, когда холдер подписывает Акт, счётчик увеличивается.

  • Верификатор запрашивает у приложения VC + счётчик + подпись счётчика (доказательство).

Вариант 2. Использование аппаратного токена (YubiKey, HSM)

  • Физический токен (как банковская карта).

  • VC записывается в токен.

  • Токен подписывает Акты и обновляет счётчик.

  • Без физического доступа к токену нельзя подписать Акт или изменить счётчик.


📌 Почему это работает

Угроза

Решение

Клонирование VC

VC — это просто данные. Без приватного ключа токена подписать VP нельзя.

Подделка счётчика

Счётчик подписывается токеном (нельзя подделать без ключа).

Обход счётчика

Токен не даёт подписать Акт без увеличения счётчика.

Потеря токена

Токен можно заблокировать (через реестр, если есть интернет).


⚠️ Но есть нюанс: физическая атака

Если Милейшев может скопировать данные с токена (взломать) — защита падает.

Решение в прототипе:
Используем эмуляцию токена через мобильное приложение с биометрией (FaceID/TouchID). Это делает клонирование затруднительным (нужно взломать защищённое хранилище iOS/Android).


🧠 Альтернативный подход (криптографический, без токена)

Есть способ сделать офлайн-верификацию без аппаратного токена, но он требует интернета хотя бы раз в сутки:

Метод «Кольцевая подпись» (Ring Signature)

  • Мама выпускает не один VC, а пачку (VC1, VC2, ... VC100).

  • Каждый VC может быть использован только один раз.

  • Когда Милейшев получает деньги, он сжигает (публикует в локальном реестре) один из VC.

  • Верификатор проверяет, что этот VC ещё не был сожжён (проверяет локальный реестр).

Проблема: Реестр должен быть общим для всех братьев. Без синхронизации — не работает.


✅ Рекомендация для вашего прототипа

Сценарий

Решение

Сложность

Демонстрация офлайн-режима

Используй эмуляцию токена (мобильное приложение с хранилищем и счётчиком).

Средняя

Прототип без токена

Прими допущение: «В офлайн-режиме мы верим, что Милейшев не клонирует VC». Для демонстрации — допустимо.

Низкая

Реальное решение

Аппаратный токен (YubiKey) + реестр статусов (слабо-онлайн).

Высокая


📌 Резюме

Твоя схема с 7 братьями ломается, если нет общего реестра.

В офлайне:

  • Без токена — Милейшев может бесконечно клонировать VC и получать деньги у разных братьев.

  • С токеном — токен ведёт счётчик использований, и братья видят, что VC уже использован.

Вывод для прототипа:
Если хочешь показать офлайн-режим — либо используй эмуляцию токена, либо чётко обозначь допущение: «В прототипе мы предполагаем, что холдер честен и не клонирует VC». Для демонстрации принципа это приемлемо. Для реального применения — нужен аппаратный токен.


не совсем верно про предъявление = 1 раз (предъявлять можно много раз, но один раз можно получить 1000р) как факт получения 1000 р (при участии счётчика токена) оказывается связан с VC? (так что следующему брату станет ясно, что ВС не компенсирован)

Предъявлять VC можно хоть 100 раз. Вопрос не в количестве предъявлений, а в том, как факт получения денег (исполнения) связывается с этим VC.

Давай разберем, как это работает с токеном и счетчиком (и без него).


🔑 Как факт получения денег связывается с VC (сценарий с токеном)

В этом сценарии сам токен Милейшева становится «живым реестром» и «свидетелем» того, что VC был исполнен.

Вот полная цепочка:

  1. Выпуск VC (Мама):

    • Мама выпускает VC для Милейшева. В поле termsOfUse она пишет: «Этот VC требует для исполнения подписи холдера (Милейшева) на токене. Токен должен вести счетчик исполненных VC для этого издателя».

    • VC подписывается мамой.

  2. Исполнение (Ты даешь деньги Милейшеву):

    • Милейшев показывает тебе VC.

    • Ты проверяешь его (подпись мамы, сроки).

    • Ты передаешь Милейшеву 1000 рублей.

    • Ключевой шаг: Ты создаешь Акт исполнения — небольшой документ, в котором говорится: «Я, [твой DID], подтверждаю, что выплатил 1000 рублей по VC [ID_VC_мамы] держателю [DID_Милейшева]».

    • Ты подписываешь этот Акт своим приватным ключом.

    • Теперь Милейшев должен подписать этот же Акт своим токеном. Токен, перед тем как поставить подпись, автоматически увеличивает внутренний счетчик исполненные_VC_для_мамы на 1 и включает новое значение счетчика в свою подпись.

  3. Результат исполнения (Что получает Милейшев):

    • Милейшев уходит с деньгами и с подписанным Актом исполнения. В этом Акте есть:

      • Твоя подпись (подтверждение выплаты).

      • Подпись токена Милейшева (подтверждение получения).

      • Новое значение счетчика токена, заверенное подписью токена.

  4. Повторное предъявление (Милейшев идет к твоему брату):

    • Милейшев снова показывает VC от мамы.

    • Брат проверяет подпись мамы — ок.

    • Брат видит в termsOfUse требование к токену.

    • Брат говорит Милейшеву: «Отлично, я вижу, что для этого VC нужен токен с подтверждением счетчика. Пожалуйста, предоставь доказательство того, что счетчик исполненных VC от мамы на твоем токене равен 0 для этого конкретного VC».

    • Милейшев не может этого сделать, потому что его токен теперь честно сообщает, что счетчик для VC от мамы равен 1 (и выдает подписанное доказательство этого).

    • Брат видит counter = 1 и говорит: «Извини, этот VC от мамы уже был исполнен. Я не могу дать тебе деньги».


🧠 Почему это работает и чем отличается от «предъявления 1 раз»

Что ты сказал

Что на самом деле

«Предъявлять можно много раз»

✅ Верно. Милейшев может показывать VC тебе и 7 братьям сколько угодно.

«Один раз можно получить 1000р»

✅ Верно. Исполнение — это однократное действие, которое меняет состояние токена.

Как связан факт получения с VC?

Через подписанный Акт исполнения. В нем есть ID VC, подпись того, кто дал деньги (ты), и подпись токена Милейшева с новым счетчиком. Этот Акт — неотъемлемое доказательство того, что по этому VC уже прошла выплата.

Что видят братья?

Они видят не просто VC, а VC + требование к токену. Они запрашивают у токена Милейшева доказательство счетчика и видят, что он уже увеличился после исполнения. Сам VC не изменился. Изменилось состояние токена Милейшева по отношению к этому VC.


⚠️ А что, если у Милейшева нет токена, а просто файл?

Тогда офлайн-защита невозможна в принципе. Милейшев может:

  1. Получить деньги от тебя.

  2. Сделать копию папки с VC и «чистым» Актом (где счетчик не увеличился).

  3. Пойти к брату и показать эту копию, скрыв факт исполнения.

Без токена у нас нет «памятного устройства», которое бы хранило состояние «исполнено/не исполнено». Любой цифровой файл можно клонировать.


🏗️ Реализация в прототипе

Для демонстрации ты можешь:

  1. Эмулировать токен через мобильное приложение, которое хранит приватный ключ и счетчик в защищенном хранилище (Keychain). Это покажет принцип.

  2. В UI АРМа добавить отображение: «VC требует подтверждения от токена. Проверка счетчика... ✅ Счетчик: 0. Исполнение возможно» или «❌ Счетчик: 1. VC уже исполнен».

  3. На уровне VC-сервиса (VcSvc) реализовать логику проверки termsOfUse и требования наличия tokenProof в VP для офлайн-режима.


📌 Итоговый ответ на твой вопрос

«как факт получения 1000 р (при участии счётчика токена) оказывается связан с VC?»

Он связан через подписанный Акт исполнения, который содержит:

  1. ID VC (ссылка на оригинальный VC мамы).

  2. Подпись верификатора (тебя), подтверждающую факт выплаты.

  3. Подпись токена холдера (Милейшева), подтверждающую получение, и новое значение счетчика (которое гарантирует, что это — первое и единственное исполнение).

Предъявляя VC, Милейшев обязан вместе с ним предоставить и доказательство от токена (в виде подписанного значения счетчика). Брат проверяет это доказательство и видит, что счетчик уже равен 1, а не 0. Так состояние «исполнено» привязано к VC через состояние токена.


На основе доступных данных, на сегодняшний день не существует широко известных или стандартизированных приложений, которые бы "из коробки" умели читать VC, связывать его атрибуты со счетчиками аппаратных токенов и автоматически генерировать соответствующие доказательства. Это связано с тем, что технология все еще находится в стадии активной разработки и стандартизации.

Ниже представлен анализ текущего состояния на основе найденных материалов.

Анализ текущего состояния

Аспект

Статус

Детали

Стандартизация "привязки к холдеру" (Holder Binding)

Активная работа и обсуждение

Концепция решает задачу: "Как верификатор может отличить законного предъявителя VC от того, кто просто скопировал файл?" . Механизм, использующий поле termsOfUse в VC для указания требований (например, необходимость подтверждения владения ключом), описан . Однако это пока не является обязательной и окончательной спецификацией.

Существующие реализации (согласно отчету W3C)

Есть, но без поддержки счетчиков токенов

Отчет по реализации модели данных VC включает множество проектов (например, vc.js, verifiable-credentials-java), которые умеют читать базовую структуру VC и проверять подписи . Однако в отчете отсутствуют тесты на поддержку какой-либо логики "счетчика", что подтверждает, что эта функциональность не является стандартной в существующих инструментах .

Механизм связи с токеном

В стадии предложений

Поле confirmationMethod (или binding) в VC предлагается для явного указания метода подтверждения, например, ссылки на публичный ключ в DID, который должен быть у холдера . Это является частью более широких дискуссий о том, как именно issuer должен "привязывать" VC к конкретному холдеру .

Счетчики для предотвращения повторного использования

Отдельная нерешенная проблема

Использование счетчика для одноразового использования VC — это ваш (и очень интересный) сценарий поверх базовой "holder binding". В известных приложениях и стандартах эта логика пока не реализована. Существующие решения фокусируются на проверке того, что предъявитель владеет ключом (подписал VP), но не на том, использовался ли этот ключ для этого VC ранее .

Что известно о существующих инструментах

  1. Базовые библиотеки: Существуют библиотеки, такие как vc.js (JavaScript) , ssi-vc (Rust) и другие, которые предоставляют API для работы с termsOfUse . Это строительные блоки, которые можно использовать для создания приложения с вашей логикой счетчика, но в них она не встроена по умолчанию.

  2. Облачные платформы: Такие платформы, как EBSI (Европейский блокчейн-сервис), уже используют поле termsOfUse для передачи сложных политик, например, требований к предъявляемым VC . Это показывает, что концепция "машиночитаемых инструкций" в VC жизнеспособна, но их обработка — это уже задача конкретного приложения или кошелька.

  3. Протоколы обмена: Протоколы, такие как OpenID for VC (OID4VP), позволяют обмениваться VP в онлайн-режиме , а для офлайн-взаимодействия используются, например, протоколы на базе DIDComm . Однако они определяют канал передачи, а не внутреннюю логику проверки счетчиков.

Вывод для вашего вопроса

Ваше видение, где приложение читает termsOfUse и на его основе запрашивает у токена конкретное доказательство (включая значение счетчика), является совершенно корректной архитектурой. Однако на данный момент:

  • Не существует готового "стандартного" приложения-кошелька, которое бы реализовывало эту логику.

  • Это задача для кастомной разработки в рамках вашего прототипа.

  • Вам нужно будет создать (или адаптировать) кошелек/приложение, которое:

    1. Умеет парсить VC и находить в нем termsOfUse с вашим кастомным типом (например, "type": "CounterBindingPolicy").

    2. Взаимодействует с API вашего эмулируемого или реального токена для получения подписанного значения счетчика.

    3. Включает это доказательство в VP.

Таким образом, вы будете пионером в реализации этой конкретной связки, опираясь на существующие стандарты и библиотеки как на фундамент.

Дополнения по теме аппаратного обеспечения

Из материалов А. Самоделова по безопасности ARM TrustZone в современных микропроцессорах с архитектурой ARMv7 и ARMv8-A и микроконтроллерах с архитектурой ARMv8-M (см. вариант 2 "глупый токен" в презентации)

Атаки с физическим доступом, включая чтение дампа памяти, — это класс атак, который спецификация TrustZone не гарантирует отразить https://ru.globals.ieice.org/en_transactions/information/10.1587/transinf.2024ICP0004/_f.

И вариант 1 "умный токен" в презентации с Java-апплетами — ещё доступен, но, похоже, уходит в прошлое (существенно меньше вариантов и активностей, чем 10 лет назад)

Журнал изменений

Дата

Перечень изменений

Автор

2026-11-05

Перенесён из архива DID-VC-итоги-2026-11-03 без изменения содержания.

Дис