Всех приветствую. Меня зовут Алексей и я блокчейн инженер.

В этой статье я хотел бы немного рассказать о сложностях построения безопасных cross-chain протоколов и поделиться тем, как мы реализовали собственный механизм консенсуса.

Вкратце: мы разработали децентрализованный протокол, обеспечивающий передачу сообщений и ассетов между блокчейнами TON и Cosmos-EVM блокчейном TAC.

Все cross-chain сообщения, циркулирующие между блокчейнами TON и TAC, “упаковываются” в merkle-дерево, после чего в контрактах консенсуса хранится только merkle-root, который позволяет верифицировать сразу множество сообщений одним значением.

Схема работы cross-chain протокола
Схема работы cross-chain протокола

Но возникает главный вопрос - кто и как верифицирует этот root?

Именно с этого момента начинается основная проблема любого cross-chain протокола: как гарантировать безопасность и достоверность данных, записываемых в смарт-контракты.

Signature-based consensus

Ключевым элементом этой безопасности является криптографическая подпись, которая проверяется в контрактах и подтверждает подлинность данных, поступающих из off-chain.

Наиболее простой и исторически ранний подход - так называемый single-signature consensus.

В этой модели один доверенный узел (валидатор), публичный ключ или адрес которого заранее зафиксирован в смарт-контракте, самостоятельно подписывает и отправляет данные.

По сути, это админ с одним ключом, от которого зависит все.

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

По этой причине большинство проектов отказались от данного подхода. Ранние реализации, такие как Avalanche Bridge v1, Wormhole v1 и Harmony Bridge, продемонстрировали его слабые места - в частности, Harmony Bridge был взломан именно из-за чрезмерной концентрации управления ключами у одного оператора.

Более безопасной альтернативой стал консенсус мультиподписи (multi-signature consensus).

В такой архитектуре смарт-контракт хранит набор публичных ключей доверенных валидаторов, и каждый из них независимо подписывает данные. Контракт верифицирует подписи и, при достижении порога t из n валидных подтверждений, признает данные достоверными.

Такой подход реализован в ряде современных протоколов, включая Wormhole, Hyperlane, Orbit Bridge и Celer.
Некоторые другие проекты, например LayerZero, используют модульную схему на основе oracle + relayer, где каждая сторона выполняет независимую верификацию данных.

Однако multi-signature решения имеют существенный недостаток: при увеличении количества валидаторов стоимость проверки множества подписей on-chain заметно увеличивается, что делает такие схемы дорогими с точки зрения затрат на оплату газа на долгой дистанции.

В наших экспериментах в сети TON было выявлено интересное поведение. Согласно документации TVM, базовая стоимость опкода CHKSIGNS, выполняющего проверку подписи Ed25519, составляет 26 газа. Однако, при одновременной проверке более десяти подписей наблюдалось резкое увеличение совокупной стоимости вычислений (до 4000 газа за подпись). По результатам тестов и переписок с командой TON выяснилось, что это поведение реализовано намеренно: фактическая вычислительная сложность проверки Ed25519-подписей на узле значительно выше, чем номинальная цена опкода, и при множественной проверке стоимость увеличивается искусственно - как механизм защиты от возможных DoS-атак.

Threshold Signature Scheme

Эти ограничения естественным образом привели индустрию к внедрению пороговых схем подписей (TSS).

TSS позволяет группе из n участников совместно сформировать единый групповой публичный ключ, при этом приватный ключ никогда не существует в полном виде, а хранится распределенно в виде долей у участников.

Далее любые t из n участников могут совместно сгенерировать одну цифровую подпись, которая корректно проверяется с помощью группового публичного ключа - так, как если бы подпись была создана одним участником.

Но TSS - это общее название протоколов, которые позволяют множеству участников создать единственную пороговую подпись.

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

TSS-ECDSA

TSS-ECDSA - семейство пороговых подписей DSA/ECDSA. Ключевые представители:

  • GG18/GG20 - ранние протоколы Gennaro-Goldfeder (позднее признаны уязвимыми и в индустрии почти не используются).

  • CGGMP21/CGG+21 - современное, улучшенное развитие GG-линейки: state-of-the-art пороговая ECDSA с идентифицируемыми абортами и безопасностью в модели без честного большинства.

  • DKLS - альтернативная линейка более строгих и формальных протоколов (пока еще широко не используется).

  • Lindell 2020 - легкий 2-of-2 вариант, популярный в MPC-кошельках.

Из-за нелинейной структуры подписи ECDSA такие протоколы требуют сложной Zero Knowledge математики, а также длительные многораундовые схемы коммуникации, но это вынужденная необходимость для создания консенсусов для EVM сетей, так как там используется как раз ECDSA подпись.

В ECDSA внутри подписи есть деление на случайный nonce и перемножение с секретным ключом, плюс часть подписи получается из координаты точки на эллиптической кривой. Из-за этого подписи нельзя просто складывать между участниками.

Примеры протоколов, реализовавших TSS-ECDSA включают Axelar, Thorchain, Entropy и инфраструктурные решения, такие как Fireblocks и Dfns.

TSS-Schnorr

TSS-Schnorr - это семейство пороговых схем подписей, основанных на линейной структуре подписи Schnorr.

В отличие от ECDSA, подпись Schnorr линейна: частичные nonce и доли подписи агрегируются по сложению. Это упрощает протокол и снижает объем ZK‑доказательств по сравнению с ECDSA.

К этому семейству относятся:

  • MuSig / MuSig2 - агрегированные Schnorr-подписи n-of-n.

  • Классический Schnorr MPC - классическая пороговая схема подписи через распределенные ключи.

  • FROST - современная round-optimized линейка протоколов для пороговых Schnorr-подписей со встроенной по дизайну защитой при конкурентных сессиях

В нашем случае, учитывая, что в TON Virtual Machine (TVM) нативной криптографической схемой является Ed25519, мы решили взять за референс протокол FROST для кривой Ed25519.

Этот протокол сочетает строгую криптографическую безопасность, минимальное количество раундов коммуникации между участниками, доказанную криптостойкость при параллельных сессиях, а также возможность верификации подписи одним вызовом встроенного TVM опкода CHKSIGNS.

Также, благодаря тому, что в TAC блокчейне был реализован precompile-контракт в модуле EVM, поддерживающий проверку подписи Ed25519, мы можем использовать ту же схему FROST для построения полноценного порогового консенсуса между TON и TAC.

Что касается других EVM сетей - будем надеяться, что EIP-665 (Ed25519 verify) когда-нибудь в будущем будет принят, что даст возможность использовать нашу реализацию консенсуса и там.

FROST

Мы решили немного модифицировать оригинальный протокол FROST, описанный в RFC 9591.

Согласно спецификации, FROST предполагает (но не требует) наличие координатора.

Координатор не обладает долей приватного ключа и не участвует в криптографических вычислениях.

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

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

Наша реализация базируется на криптографическом ядре FROST, но использует модифицированную коммуникационную модель без координатора.

Вместо асинхронного обмена через централизованный узел мы применяем синхронную p2p-коммуникацию, где каждый валидатор выполняет роль координатора.

Такая модель ближе к BFT-подходам (Tendermint, HotStuff), где все участники проходят согласованные раунды.

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

Хотя синхронная раундовая модель требует задания жестких временных интервалов для работы валидаторов на каждом этапе, мы решили остановиться на таком варианте, так как он показался нам оптимальным с точки зрения скорости реализации, надежности и простоты отладки.

Так сформировалась наша модификация - BFT-style, round-based, synchronous distributed FROST - протокол, сочетающий криптографическую строгость оригинального FROST с синхронной моделью коммуникации.

Дополнительно отметим, что наша реализация требует порог консенсуса больше, чем 50% от общего числа участников.

Транспортный уровень и взаимодействие валидаторов

Для организации обмена сообщениями между валидаторами протокол использует децентрализованный транспортный слой, построенный на базе libp2p - надежного однорангового сетевого стека, применяемого во множестве современных блокчейн-систем.

Каждый узел-валидатор в сети обладает уникальной криптографической идентичностью, представленной ключом Ed25519, который закреплен за ним в смарт-контракте on-chain. Этот ключ используется для проверки подлинности участника при установлении соединений. Таким образом, каждый узел всегда точно знает, с кем он общается, и что сообщения действительно приходят от валидаторов, указанных в смарт-контракте.

Дополнительно к этому, все соединения между узлами автоматически шифруются через TLS, встроенный в libp2p. Благодаря этому любой трафик в сети защищен от перехвата, а попытки подмены узла становятся невозможны.

Обмен данными между участниками осуществляется через pub/sub-механику GossipSub, которая обеспечивает широковещательную и отказоустойчивую доставку сообщений внутри сети. Pub/sub позволяет узлам синхронизировать состояние без централизованных серверов и автоматически адаптироваться к изменениям в составе валидаторов.

Благодаря этой архитектуре транспортный уровень обеспечивает:

  • Децентрализованную маршрутизацию: узлы взаимодействуют напрямую через libp2p.

  • Криптографическую идентификацию: каждый участник подтверждает свою подлинность Ed25519-подписью.

  • Шифрование канала: TLS обеспечивает защищенность и аутентификацию соединений.

  • Отказоустойчивость и масштабируемость: GossipSub быстро адаптируется к изменениям сети.

В совокупности это формирует безопасную и самодостаточную одноранговую p2p-сеть, которая обеспечивает коммуникацию между валидаторами и служит надежным транспортным уровнем для нашего FROST-based консенсуса.

Distributed Key Generation (DKG)

Для формирования группового публичного ключа и индивидуальных приватных долей ключа валидаторов используется синхронный раундовый процесс распределенной генерации ключей (DKG).

Сессия DKG состоит из пяти последовательных раундов: Join, JoinAck, Deal, DealAck и Final.

В ходе этих раундов валидаторы формируют и публикуют сообщения в gossip сеть. Каждое сообщение, помимо полезных данных, содержит собственную криптографическую подпись отправителя.

Хотя libp2p уже на транспортном уровне обеспечивает криптографическую идентификацию узлов, отдельная подпись необходима для обработки жалоб и разрешения конфликтов.

Если один участник обвиняет другого в нарушении, он может предъявить оригинальное сообщение нарушителя с его подписью, и другие валидаторы смогут самостоятельно убедиться в подлинности данных и отсутствии подмены.

Кратко рассмотрим каждый раунд.

Join Round

Цель этого раунда - сформировать актуальный список валидаторов, участвующих в DKG-сессии.

Каждый валидатор, который в данный момент доступен и готов принять участие в процессе, генерирует эфемерную пару ключей Диффи–Хеллмана и публикует сообщение Join, в котором указывает свой публичный DH-ключ, а также Schnorr-доказательство, подтверждающий знание соответствующего приватного ключа.

Этот ключ впоследствии используется другими участниками для шифрования приватных долей (shares) при помощи симметричного ключа, полученного из DH-пары “отправитель-получатель”.

JoinAck Round

Цель этого раунда - зафиксировать согласованный список участников, которые успешно прошли стадию Join.

Каждый валидатор, получив все валидные Join-сообщения от других узлов, проверяет корректность Schnorr proof у каждого DH-ключа и формирует локальный отсортированный список участников DKG.

После верификации все валидаторы публикуют сообщение JoinAck, содержащее агрегированный коммитмент от их локального списка ValidatorSet.

Каждый валидатор, на основании полученных сообщений JoinAck подсчитывает количество голосов за каждый из пришедших списков. Если какой-то список набирает как минимум t голосов, то все валидаторы из этого списка считаются утвержденными к участию в DKG сессии. Также, основываясь на списке утвержденных участников, каждому участнику детерминировано выдается целочисленный id, который впоследствии используется для вычисления приватных долей и самой подписи.

Deal Round

Цель этого раунда - распределить приватные доли (shares) между всеми участниками и опубликовать публичные коммитменты, необходимые для последующей верификации корректности распределения.

Далее каждый участник i (дилер) создает собственный случайный многочлен степени t-1. Формально он имеет вид:

f_i(x) = a_{i,0} + a_{i,1}x + a_{i,2}x^2 + \dots + a_{i,t-1}x^{t-1}

где коэффициенты a_{i,k} выбираются случайным образом, а t - минимальное число участников, необходимое для генерации пороговой подписи.

Для каждого коэффициента многочлена участник вычисляет коммитмент по схеме Feldman VSS:

C_{i,k} = a_{i,k} \cdot G

где G - генератор выбранной группы (в нашем случае Ed25519).

А также вычисляется Schnorr-доказательство для коэффициента a_{i,0}:

  1. Генерируется случайный nonce k и вычисляется коммитмент K:
    K = k \cdot G

  2. Вычисляется детерминированный salt как конкатенация контекстных данных сессии с индивидуальной меткой для a_{i,0} пруфа (любая строка):
    \text{salt} = (\text{sessionId} \,\|\, \text{text}(a0\text{proof}Tag))

  3. Вычисляется Challenge с приведением к полю кривой Ed25519:
    c = H(\text{salt} \,\|\, G \,\|\, C_{i,0} \,\|\, K)

  4. И наконец ответ:
    s = k + c \cdot a_{i,0}

В качестве всего доказательства используется комбинация {c,s}, а также C_{i,0} из опубликованных коммитментов.

Теперь дилер должен вычислить приватную долю для каждого участника j как значение полинома для целочисленного id участника-получателя:

s_{i \to j} = f_i(j)

Чтобы обеспечить конфиденциальность этих долей, они шифруются с помощью симметричного ключа, полученного из DH-пары между дилером и получателем. Каждая доля шифруется алгоритмом AEAD ChaCha20-Poly1305.

Ключ:
K_{i,j} = \mathrm{KDF}\big( \mathrm{DH}(d_i, D_j),\ \text{SessionID} \big)

Cipher:
\mathrm{ciphertext}_{i \to j} =\mathrm{Enc}_{K_{i,j}}\big(s_{i \to j},\\mathrm{AAD} = (\text{SessionID},\ i,\ j)\big)

После генерации и шифровании долей участник публикует сообщение Deal, которое включает:

  • Полный набор публичных коммитментов C_{i,k}.

  • Schnorr-доказательство знания коэффициента a_{i,0}.

  • Зашифрованные приватные доли для всех участников.

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

DealAck Round

Цель этого раунда - подтвердить корректность полученных долей или зафиксировать жалобы на нечестных дилеров.

Каждый участник проверяет все полученные Deal сообщения, расшифровывает свою долю, сверяет ее с публичным коммитментам, соответствующим его доле.

Также проверяется валидность знания дилером коэффициента a_{i,0} благодаря Schnorr-доказательству.

Любой участник может проверить доказательство попытавшись восстановить Challenge и сравнить его с Challenge от дилера:

  1. Вычисляем R:
    R_i = s_i G - c_i C_{i,0}

  2. Востанавливаем Challenge:
    c = H(\text{salt} \,\|\, G \,\|\, C_{i,0} \,\|\, R_i)

Если получившийся Challenge равен Challenge от дилера, то доказательство считается валидным.

Так как это может проверить каждый участник, то в случае невалидного доказательства сообщение с жалобой не формируется, а дилер помечается как faulty у всех других валидаторов детерминировано.

Если все валидно, то участник отправляет Ack подтверждение:

Ack=true

Если доля, предназначавшаяся данному валидатору, не валидна (не расшифровывается или не совпадает с коммитментами по Фельдману), валидатор формирует жалобу, включающую оригинальное сообщение дилера и DLEQ-доказательство:

Ack=false
Complaint={OriginalMessage,DLEQ-proof}

DLEQ-доказательство - это zero-knowledge доказательство того, что два эллиптических пункта порождены одним и тем же секретом, не раскрывая этот секрет.

DLEQ-доказательство позволяет другим участникам убедиться, что получатель действительно обладает корректной DH-парой и может расшифровать долю. Оно же исключает возможность ложных обвинений. 

Если жалоба истинна, дилер считается нечестным; если же доказательство расшифровки подтверждает корректность доли, виновным признается отправитель жалобы.

Завершая раунд, каждый участник публикует сообщение DealAck, содержащее пару dealer -> ack для всех дилеров, от которых он получил Deal-сообщение.

Final Round

Цель финального раунда - определить множество честных участников, исключить узлы, нарушившие правила на предыдущих этапах, и вычислить итоговые значения: индивидуальную приватную долю участника и групповой публичный ключ.

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

Участник считается честным, если он набрал достаточное ( >= t ) количество голосов от других валидаторов, подтверждающих корректность его долей и корректность поведения в Deal/DealAck раундах, а также не получил ни одной корректной жалобы (complaint)

После определения множества честных участников каждый валидатор вычисляет свою итоговую приватную долю:

S_i = f_i(i) + \sum_{\substack{j \in \mathrm{Honest} \\ j \neq i}} s_{j \to i}

То есть приватная доля участника - это сумма всех корректных долей, полученных от честных дилеров, включая собственную.

Групповой публичный ключ формируется как сумма всех C_0 коммитментов честных участников:

P = C_{i,0} + \sum_{\substack{j \in \mathrm{Honest} \\ j \neq i}} C_{j,0}

Для каждого участника j мы также определяем публичную долю верификационного ключа vkShare_j.

Это точка на кривой, соответствующая его приватной доле S_j, и она используется для проверки частичных подписей данного валидатора.

\mathrm{vkShare}_i= \left( \sum_{j \in \mathrm{Honest}} s_{j \to i} \right) \cdot G= \sum_{j \in \mathrm{Honest}} \left( \sum_{k=0}^{t-1} C_{j,k} \cdot i^k \right)

Как результат всей сессии валидатор сохраняет:

  • Свою итоговую приватную долю S_i.

  • Список всех валидных участников и их целочисленный id.

  • Каждую публичную долю участника vkShare_j.

  • Групповой публичный ключ P.

После успешного завершения DKG-сессии валидаторы с помощью multisig-консенсуса записывают полученный GroupPublicKey в контракты консенсуса. В дальнейшем этот ключ используется смарт-контрактами для верификации всех групповых пороговых подписей.

Поскольку DKG-сессия проводится крайне редко, использование multisig-консенсуса на этом шаге не оказывает существенного влияния на суммарные затраты газа протокола.

Процесс формирования подписи

Процесс подписи также организован в виде синхронной раундовой сессии, аналогично DKG, и состоит из четырех основных раундов: Join, DiEi, DeriveZi и Final.

Join Round

Цель раунда - определить множество валидаторов, которые будут участвовать в подписи конкретного сообщения m.

Каждый валидатор публикует сообщение Join, подтверждая свою готовность участвовать в формировании подписи.

После завершения раунда все валидаторы собирают список участников, принявших участие в Join, и формируют множество подсессий. В каждой подсессии содержится набор cosigners, мощность которого должна быть не меньше порога t.

Для каждой подсессии вычисляется ее идентификатор (subsession id) как хэш от конкатенации идентификатора всей сессии с отсортированным агрегированным списком всех участников этой подсессии:

\mathrm{ssid} = H\!\left( \mathrm{session\_id} \,\|\, \mathrm{sort}\bigl(\mathrm{peerId}_1, \ldots, \mathrm{peerId}_t\bigr) \right)

Для успешного завершения процесса подписи строго необходимо, чтоб все выбранные cosigners отправили свои данные. Поэтому мы ввели предположение, что кто-то из валидаторов может по какой-либо причине выйти из процесса (сетевой сбой, временная недоступность, рестарт ноды), поэтому протокол заранее формирует несколько подсессий, исключая по cosignersSlack участников из полного множества allJoined. Пока что мы остановились на параметре cosignersSlack=1. Т.е. если во время сессии подписи отвалится один участник, подсессия, где нет этого участника все равно сможет успешно завершится.

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

DiEi Round

Когда все подсессии были сформированы и каждый набор сosigners известен, каждый участник для каждой своей подсессии генерирует коэффициенты Лагранжа, основываясь на целочисленных id всех cosigners.

Лагранжев коэффициент λ_i - это просто математический множитель, который позволяет правильно объединить частичные подписи участников, чтобы итоговая подпись соответствовала единому секретному ключу группы.

Все приватные доли s_i - это значения многочлена f(x) в разных точках x. Чтобы восстановить значение этого многочлена в точке f(0), нужно взвешивать доли определенным образом. Для этого и нужны коэффициенты Лагранжа.

\lambda_i = \prod_{\substack{j \in S \\ j \neq i}} \frac{j}{j - i}

После этого каждый участник для каждой подсессии, генерирует пару случайных одноразовых nonce (d_i, e_i) и публикует их коммитменты (D_i, E_i).

DeriveZi Round

После того, как собраны nonce-коммитменты всех участников, каждый валидатор для каждой своей подсессии должен вычислить:

  • Агрегированный nonce R для подписи.

  • Сhallenge c.

  • Свою частичную подпись z_i.

Начнем с объяснения агрегированного nonce R.

Для начала валидатор должен вычислить binding factor.

Binding factor (r_i) - это детерминированный коэффициент, который связывает оба nonce участника (d_i и e_i) с контекстом конкретной подсессии.

Он предотвращает любые попытки валидатора изменить значения E_i и D_i  после публикации и тем самым манипулировать итоговым агрегированным nonce R.

r_i должен быть одинаковым для всех честных участников и вычисляться строго детерминированно из публичных данных подсессии.

Для каждого участника i формируется контекстная строка, включающая:

  • Контекстные данные подсессии (subsession id).

  • Целочисленный идентификатор участника.

  • Подписываемое сообщение m.

  • Набор всех коммитментов (D_j, E_j) участников подсессии.

Затем binding factor вычисляется как хэш этой контекстной строки:

r_i = H\big(ssid,i\,\|\, m\,\|\, \{ j, D_j, E_j \}_{j \in \mathrm{cosigners}}\big)

Теперь валидатор может вычислить каждую часть R_i для всех участников:

R_i = D_i + r_i \cdot E_i

И общий R подсессии, как сумма всех R_i:

R = \sum_{i \in \mathrm{cosigners}} R_i

На основе R, GroupPublicKey и сообщения m вычисляется общий Ed25519 challenge c:

c = \mathrm{SHA512}\!\left( R \,\|\, \mathrm{GroupPublicKey} \,\|\, m \right)

После чего валидатор формирует свою частичную подпись:

z_i = d_i + r_i \cdot e_i + \lambda_i \cdot S_i \cdot c

Где:

  • d_i, e_i - приватные nonce валидатора;

  • r_i - binding factor;

  • λ_i - коэффициент Лагранжа;

  • S_i - приватная доля валидатора из DKG;

  • c - Ed25519 Challenge.

После этого каждый участник публикует свои частичные подписи (z_i) для каждой своей подсессии.

Final Round

Цель Final Round - проверить корректность частичных подписей всех участников и сформировать итоговую пороговую подпись (R,Z), которая затем будет опубликована в смарт-контракты TON и TAC.

Первая подсессия, которая успешно сформирует валидную подпись, завершает всю сессию подписи.

После завершения DeriveZi раунда каждый участник в рамках всех своих подсессий хранит:

  • агрегированный nonce

  • общий challenge

  • частичные подписи всех участников

Теперь нам нужно для каждой подсессии проверить валидность z_i каждого участника, используя вычисленный vkShare_i для каждого участника на финальном этапе DKG:

z_i \cdot G \stackrel{?}{=} R_i + c \cdot \lambda_i \cdot \mathrm{vkShare}_i

Если это равенство не выполняется, то мы помечаем участника как faulty, а данную подсессию помечаем как failed и переходим к обработке следующей подсессии.

Если в подсессии все z_i валидны, то мы вычисляем Z как сумму всех z_i:

Z = \sum_{i \in \mathrm{cosigners}} z_i

И итоговую подпись (R,Z).

Если итоговая подпись проходит проверку, то валидатор сохраняет себе ее и завершает процесс.

Поскольку подпись совпадает с форматом обычной Ed25519 подписи, она может быть проверена:

  • в TVM через один опкод CHKSIGNS

  • в TAC EVM через встроенный precompile проверки Ed25519

  • стандартным Ed25519 verify в Go

Теперь любой валидатор может использовать получившуюся у него подпись для установки root в контрактах консенсуса на сетях TON и TAC, после чего исполнители (executors) могут исполнять cross-chain сообщения, предоставив merkle proof.

Итог

На тестовом стенде из 30 валидаторов мы получили стабильное время создания пороговой подписи около 8 секунд. Для наших задач этого вполне достаточно, хотя в будущем мы рассмотрим возможность реализации частично-асинхронной модели коммуникации, для избавления от жестких временных интервалов для раундов, что позволит еще больше увеличить скорость работы консенсуса.

В целом можно сказать одно: сделать консенсус одновременно дешевым, быстрым и безопасным - задача далеко не тривиальная. Но мы довольны получившимся результатом.

Спасибо всем, кто дочитал до этого момента.

Будем рады вашей обратной связи и вопросам.

Авторы статьи: Aleksey Kokinos ( @Ak_Koks ), Dmitry Vedernikov ( @sirvff ).