Проверка подтверждения аккаунта Symbol (часть 1) — Автор: gimre
Статья от основного разработчика NEM (gimre).
В публичной сети Symbol, есть уникальная функция, которая называется подтверждением состояния. Данная функция описана не достаточно подробно, поэтому большинство пользователей не понимают, что дает эта функция.
Доказательства состояния позволяют ДОКАЗАТЬ какой-либо третьей стороне, что на высоте блока X состояние вашего аккаунта (или состояние мозаики, или состояние пространства имен, или любое другое состояние) было равно Y.
Но есть одно примечание: сейчас нет способа, чтобы получить через API (интерфейс программирования приложений) состояние на заданной высоте блока, поэтому предполагается, что состояние было сохранено на нужной высоте. Самое приятное то, что такое состояние, может быть валидировано (подтверждено) верификатором без доверия.
Состояние сериализации
Давайте разберем этот аккаунт в тестовой сети Symbol: TAKUOCDJH4KUDYP7ZH5HMW43QXYXTLFEDQUR4MI
Сведения об учетной записи можно получить, запросив конечную точку REST API:
/accounts/<account-id> это выглядит следующим образом:
{
«account»: {
«version»: 1,
«address»: «98154708693F1541E1FFC9FA765B9B85F179ACA41C291E31»,
«addressHeight»: «119481»,
«publicKey»: «13182CF21C0C13BA3FB5401EEED94D274C4305A54017ABCA7CDDEB85A173F765»,
«publicKeyHeight»: «119490»,
«accountType»: 0,
«supplementalPublicKeys»: {},
«activityBuckets»: [],
«mosaics»: [
{
«id»: «091F837E059AE13C»,
«amount»: «8539426394»
}
],
«importance»: «0»,
«importanceHeight»: «0»
},
«id»: «<node-based, not important>»
}
В настоящее время (symbol python core-sdk) не позволяет сериализовать состояние аккаунта, но состояние аккаунта имеет его определение внутри (catbuffer-schemas). Итак, давайте сделаем ручную сериализацию данных.
Аккаунт имеет важность = 0, что означает, что это не очень ценный аккаунт, тем самым значительно облегчая задачу.
Последнее, что нужно сделать перед проверкой состояния аккаунта, это вычислить хэш sha3 сериализованных данных.
010098154708693f1541e1ffc9fa765b9b85f179aca41c291e31b9d201000000000013182cf21c0c13ba3fb5401eeed94d274c4305a54017abca7cddeb85a173f765c2d20100000000000000000001003ce19a057e831f095a4efdfc01000000
Результирующий хэш состояния аккаунта sha3 равен:
9532475d9217848ca629e690c89470f18c95497d8913233e74fa32b802b3c5d5
Проверка состояния дерева хешей
В 4 главе технического документа Symbol (catapult), подробное описано дерево Меркла, поэтому в этой статье это не будет повторяться.
Давайте запросим текущий путь дерева Меркла для этого аккаунта. Конечная точка REST API (передача состояния представления): /accounts/<account-id>/merkle, обратные данные выглядят следующим образом:

Путь Меркла к рассматриваемому аккаунту
Передача состояния представления (REST API), возвращает дерево Меркла в “сырой формат”, тем самым необходимо обработать это с помощью синтаксического анализа, который легче обрабатывать.
Обратные путь дерева Меркла идет от вершины дерева к основанию. Проверка может быть в любом направлении — снизу вверх или сверху вниз. При визуализации дерево Меркла будет выглядеть следующим образом:

Визуализация полного пути дерева Меркла
Были сокращены ссылки = хэши. Это полное дерево, поэтому недостающие ссылки заменяются 00-хешами).
Путь — это просто хэш ключа. В случае кеширования состояния учетной записи ключом является просто адрес учетной записи. Так что в случае данного аккаунта TAKUOCDJH4KUDYP7ZH5HMW43QXYXTLFEDQUR4MI путь будет следующим:
>>> sha3_256(unhexlify(‘98154708693F1541E1FFC9FA765B9B85F179ACA41C291E31’)).hexdigest()
E220E4E4BCF533F0E0082F28E65B8EA5A278D255DB22D61D097A2F9008676F3A
Каждая ветвь дерева может содержать непустой путь, но в приведенном выше примере путь всегда пуст поэтому двигаясь сверху вниз, необходимо брать правильные полубайты (половина байта будет называться полубайтом).
По порядку: E, 2, 2, 0, поэтому «оставшийся» путь E4E4BCF533F0E0082F28E65B8EA5A278D255DB22D61D097A2F9008676F3A
Примечание: если невозможно пройти по дереву Меркла сверху вниз, используя правильные ветви, это означает, что дерево Меркла было изменено.
Теперь можно легко заметить, что значение листьев с нужным хешем («type»: 255) равно хешу sha3, вычисленному ранее. Это означает, что одна проверка сделана.
{
«type»: 255,
«path»: «E4E4BCF533F0E0082F28E65B8EA5A278D255DB22D61D097A2F9008676F3A»,
«encodedPath»: «20E4E4BCF533F0E0082F28E65B8EA5A278D255DB22D61D097A2F9008676F3A»,
«nibbleCount»: 60,
«value»: «9532475D9217848CA629E690C89470F18C95497D8913233E74FA32B802B3C5D5»,
«leafHash»: «39D61E874BE3A301D1FEE4DDA1D2F6D53030004A51E6399BFB6F58EE35218EC4»
}
Теперь что нужно сделать верификатору, так это проверить все хеши на пути. Начнем снизу, так будет проще.
Лист Хеш (leafHash) — это хэш конкатенированного закодированного пути (*) (encodedPath) поэтому:
Как получить кодированный путь из пути выходит за рамки этого поста, любопытным читателям следует взглянуть на главу 4 в техническом документе Symbol.
>>> sha3_256(unhexlify(’20E4E4BCF533F0E0082F28E65B8EA5A278D255DB22D61D097A2F9008676F3A’) + unhexlify(‘9532475D9217848CA629E690C89470F18C95497D8913233E74FA32B802B3C5D5’)).hexdigest()
39D61E874BE3A301D1FEE4DDA1D2F6D53030004A51E6399BFB6F58EE35218EC4
Это значение совпадает.
Полубайт пути, который привел нас к этому листу хеша, имел значение 0. Это означает, что «ссылка» в 0-м элементе на уровне 4 должна соответствовать этому хешу, и это действительно так.
Аналогично хеш ветка (branchHash) — это хэш объединенного закодированного пути и всех ссылок на данном уровне. Как отмечалось ранее, недостающие элементы должны быть заполнены 00-хешем. Таким образом, для уровня 4 закодированный путь равен «00», и это дает нам:
>>> zero = unhexlify(‘00000000000000000000000000000000000000000000000000000000000000’)
>>> sha3_256(unhexlify(’00’) + u(’39D61E874BE3A301D1FEE4DDA1D2F6D53030004A51E6399BFB6F58EE35218EC4′) + zero * 3 + unhexlify(‘6A69ADA0538FC9582D813619288B400038286522206FEA14D231F0D9775900E3’) + zero * 11).hexdigest()
B1508023DFF34155479B81C93EE43926F590E59E0CEA66F4633D5929B809AC34
Это также можно проверить здесь. И вы можете проверить, что это соответствует хэшу ветки на уровне 4.
Путь, который привел нас к данному результату, был на уровне 2, а ссылка на уровне 3 в позиции 2 соответствует вычисленному хэшу.
Теперь нам нужно повторить процесс, я вставлю инструмент, который вычисляет правильно хэш ветки BranchHash:
Расчетный корневой хеш-код: B6B9F48079B27914FFE030B8CBBE6C81ED30FEB4E007946962C4283CBD99C581
Наконец, доказывающий может проверить, что вычисленный хэш соответствует хешу дерева состояний на той конкретной высоте, для которой был получен путь к дереву Меркла: http://explorer.testnet.symboldev.network/blocks/173056
Теперь с помощью шорткат, мы ссылаемся на эксплорер блоков Symbol, но чтобы ссылаться без доверия, верификатор должен собрать все заголовки блоков, только сами заголовки, не нужно фактически проверять их содержимое. Поэтому достаточно проверить, что хэш состояния аккаунта в этом блоке действительно соответствует вычисленному хэшу.
Резюме:
Доказательство обеспечивает:
- состояние счета
- путь к дереву Меркла на заданной высоте
Верификатор:
- сериализует состояние учетной записи,
- проверяет сериализованное состояние по пути дерева Меркла
- проверяет хэш корня состояния по заголовку блока
http://phrack.org/issues/49/14.html
https://docs.symbolplatform.com/symbol-openapi/v1.0.1/#operation/getAccountInfo
https://docs.symbolplatform.com/symbol-openapi/v1.0.1/#operation/getAccountInfoMerkle
Оригинал статьи: https://ncosigimcitynre.medium.com/verifying-symbol-account-state-proofs-for-fun-and-profit-part-1-3dfedfc19cb4
Автор: gimre
https://twitter.com/NCOSIGIMCITYNRE/status/1405505634431287298
Comments are closed