
Привет, Хабр!
Я Ирина Слонкина из отдела безопасности распределенных систем Positive Technologies. Вместе с коллегами исследую безопасность смарт‑контрактов и блокчейн‑приложений. Конечно, всегда интересно вникнуть вглубь каждой технологии, вышедшей на рынок. В этой статье я расскажу про криптографический протокол PLONK, один из самых интересных протоколов в блокчейн‑индустрии.
PLONK (Permutations over Lagrange‑bases for Oecumenical Noninteractive arguments of Knowledge) — zk‑SNARK*, разработанный в 2019 году Ариэлем Габизоном и соавторами (Zachary J. Williamson, Oana Ciobotaru). PLONK позволяет доказать знание набора переменных, удовлетворяющего некоторой детерминированной программе (арифметической схеме), не разглашая их. Значения некоторых из этих переменных могут быть фиксированы. Например, можно доказать знание строки, хеш от которой равен определенному числу.
С момента появления PLONK ценят за компактные доказательства, быструю верификацию и многоразовую обновляемую доверительную настройку, поэтому в наши дни он широко используется в различных приложениях. Тем важнее исследовать его безопасность.
*zk‑SNARK (Succinct Non‑interactive ARgument of Knowledge, краткие неинтерактивные аргументы знания) — один из ключевых типов доказательств с нулевым разглашением наравне со STARKs (Scalable Transparent ARgument of Knowledge, краткие прозрачные аргументв знания), DARK (Diophantine Arguments of Knowledge, диофантовы аргументы знания) и Bulletproofs. Отличительными чертами являются небольшой размер доказательства (<1 КБ), высокая скорость верификации и необходимость доверенной настройки в начале протокола. Так как в PLONK используется универсальная доверенная настройка, его иногда выделяют из SNARK'ов в отдельный тип доказательства. Вот здесь можно почитать подробнее про zk‑SNARKs.
Арифметическая схема

Программа задается посредством арифметической схемы из n узлов, каждый из которых имеет два входа (ai, bi) и один выход (ci) — элементы поля ? простого порядка. Между ними выполняется соотношение ,
где QLi, QRi — коэффициенты при каждом из входов, QOi — при выходе, QMi — при произведении входов и QCi — при единице. Например, для второго узла представленной схемы коэффициент при входе a2 равен 1, при b2 — 2; монома, содержащего их произведение a2b2, в выражении нет, поэтому QM равняется 0; QC равняется трем, а выходу соответствует коэффициент −1.

Помимо операций внутри узлов, важно закодировать соотношения между ними, а именно равенство между входами и выходами различных узлов. Для этого в мультипликативной группе поля ? выбирается элемент g порядка n (если такого не существует — минимального порядка, превышающего n) и строится подгруппа из n элементов, которыми индексируются узлы схемы и входы ai. Ее смежные классы k1H, k2H исаользуются для индексации bi и ci.
Колонки таблицы SA, SB, SC изначально заполняются элементами H, k1H и k2H соответственно. Затем в ней меняются между собой местами индексы равных между собой элементов: c1 и a2 (розовые ячейки; с1 изначально соответствовал индекс k2, a2 — индекс g), c2 и b3 (голубые ячейки; с2 индексируется элементом k2g, b3 — k1g2).
Итак, арифметическая схема задается посредством наборов селекторов для каждого узла и подстановки σ, кодирующей равенство между определенными переменными внутри схемы. В ходе предобработки для них с помощью базиса Лагранжа —
, если i = j; 0 в противном случае — строятся многочлены
которые в точке gi-1, соответствующей узлу i, принимают значение селектора/подстановки qLi, …, SCj в этом узле.
Как работает протокол PLONK
На вход протокола PLONK подаются три разновидности параметров: входы доказывающего, входы проверяющего и общие входы.
-
Общие входы:
задающие схему —
общие переменные Public Input — например, значение хеш-функции, знание прообраза для которой доказывается;
reference string
— базовая точка эллиптической кривой [1]1, умноженная на различные степени секретного числа x. Само число х удаляется сразу же после формирования r.s. Если доказывающему нужно посчитать коммитмент (то есть значение какого-либо многочлена в точке x), он может сделать это, только складывая между собой компоненты r.s., домноженные на коэффициенты многочлена при соответствующих степенях. Так как дискретное логарифмирование на эллиптической кривой в общем случае сложная операция, а умножение и деление друг на друга для точек эллиптической кривой не определено, предоставление валидного коммитмента в случае безошибочной реализации протокола с близкой к единице вероятностью означает знание коэффициентов многочлена, а также принципиальную возможность домножить на них точку эллиптической кривой;
-
Входы доказывающего:
весь набор переменных ai, bi, ci — так называемый witness;
-
Входы проверяющего:
— коммитменты многочленов в точке x:
(произведение базовой точки эллиптической кривой на qL(x)).
В ходе выполнения протокола доказывающий должен убедить проверяющего, что его набор назначений соответствует:
общим входам PI;
селекторам схемы;
подстановкам.
Для этого, в частности, требуется evaluation proof — доказательство того, что значение многочлена в заданной точке соответствует его коммитменту.
Доказательство соответствия селекторам
Корректные входы ai, bi и выходы ci узлов схемы должны удовлетворять условию .
Из общих входов доказывающему доступны многочлены , в каждой точке, соответствующей узлу i, принимающие значения, равные соответствующим коэффициентам. В первом раунде он строит такие же многочлены для входов/выходов, а в третьем перемножает их между собой в соответствии с изначальным условием, получая многочлен
. Ожидается, что в каждой точке группы H он будет принимать значение 0. Для доказательства этого факта строится обнуляющий многочлен ZH, корнями которого являются все элементы группы H. Если назначения удовлетворяют селекторам, многочлен eq(X) будет делиться на ZH нацело. Этот факт доказывается с помощью коммитмента. Так как доказывающему не известно x, он не может посчитать числитель и знаменатель отдельно и произвести деление. В результате получается многочлен t(X).
Первые слагаемые многочленов a(X),b(X),c(X) вида (riX + rj)ZH служат для маскировки назначений. Они не влияют на делимость eq и позволяют выполнить условие zero knowledge: значение a(X) в определенной точке не дает информации о соответствующем назначении.
Раунд 1
В третьем раунде t(X) разбивается на три части в целях оптимизации.
Раунд 3
В интерактивном протоколе челленджи (случайные переменные) доказывающий получает от проверяющего. В неинтерактивном они заменяются хешами от переменной transcript, в которую при инициализации помещаются PI и common input, а после каждого раунда — новые компоненты доказательства. С помощью transcript доказывающий и проверяющий могут генерировать одинаковые случайные переменные: первый — в ходе создания доказательства, второй — в ходе его проверки. В реализациях со слабым преобразованием Фиата — Шамира в transcript отсутствуют некоторые входы протокола, что позволяет сгенерировать их уже после доказательства.
Доказательство соответствия PI
Многочлен PI(X), построенный аналогичным образом, входит в eq(X) в качестве слагаемого. Поправка на PI закладывается в многочлен qC(X) на этапе его генерации из селекторов схемы.
Доказательство соответствия подстановке
Даны две последовательности . Утверждается, что они одинаковы. Как можно проверить этот факт без использования понятия упорядоченности?
В PLONK для этих целей вводится индексация последовательностей с помощью компонентов witness: . Задав случайные коэффициенты β и ɣ, можно поставить в соответствие последовательностям произведения:
...
Если последовательности идентичны — сравнение будет
выполнено. Обратное в общем случае неверно, но вероятность «ложного срабатывания» достаточно мала, особенно если коэффициенты действительно случайны и неподконтрольны доказывающему.
Во втором раунде формируется многочлен ρ(X), соответствующий значению выражения под произведением в левой части этого сравнения (за тем исключением, что, кроме левых входов, включает также правые входы и выходы). Но доказывающий не может просто перемножить ρ(X) для всех X∈H и отправить коммитмент для 1.
Раунд 2
Для доказательства с помощью базиса Лагранжа строится многочлен z(X), для каждого элемента множества H равный произведению
Доказывающему необходимо доказать, что:
=1, то есть
;
корректны все шаги по построению
, то есть
.
Это делается в третьем раунде с помощью уже упоминавшегося здесь многочлена t(x): второй его компонент доказывает второе утверждение, а третий — первое. Если числитель не обнуляется во всех точках H — он не делится на ZH нацело, а следовательно, для него не может быть вычислен коммитмент в секретной точке x с использованием reference string.
Раунд 3
Evaluation proof
В ходе выполнения протокола проверяющий должен непосредственно убедиться, что все полученные им коммитменты вычислены верно и соответствуют друг другу. Для этого проверяющий самостоятельно повторяет действия доказывающего, составляя компоненты доказательства из коммитментов. Так как проверяющий не может перемножать между собой коммитменты (точки на эллиптической кривой) и не должен выполнять вычислительно сложные действия, доказывающий вычисляет целочисленные evaluations — открывает значения компонентов доказательства в случайной точке ,
после чего формирует линеаризационный многочлен R(X), заменяя в числителе t(x) многочлены на их evaluations
.
В пятом раунде доказывается соответствие evaluations ранее сформированным коммитментам. Согласно теореме Безу, многочлен F(X)−F(ζ) делится без остатка на X−ζ. Только в этом случае доказывающий может вычислить коммитмент для частного (F(X)−F(ζ))/(X−ζ). Аналогичным образом Wzg(Х) служит для доказательства значения z(X) в точке ζg.
Раунд 4
Раунд 5
Проверка доказательства
В ходе проверки в первую очередь определяется принадлежность компонентов доказательства заявленному множеству, затем с помощью transcript из общих входов, PI и компонентов доказательства вычисляются челленджи , равные аналогичным челленджам доказывающего, и u. Вычисляются
Затем проверяющий повторяет вычисление r(X), в целях оптимизации разбивая его на две части: полиномиальную r’(X) и константную .
формируется из самостоятельно вычисленных челленджей, значений многочленов в точке и полученных от доказывающего evaluations; при построении r’(X) также используются коммитменты для cелекторов и подстановок из входов проверяющего и коммитменты для
, переданные доказывающим:
После этого проверяющий формирует из коммитментов и evaluations аналог :
Финальная проверка осуществляется путем сравнения
где — вторая базовая точка эллиптической кривой,
— функция, отображающая пару точек эллиптической кривой в элемент конечного поля и обладающая следующими свойствами:
тождественность: e(P,P) = 1;
-
билинейность — спаривание суммы равняется произведению спариваний по любому из аргументов:
следствие билинейности — коэффициент при любом из аргументов можно вынести как степень спаривания:
невырожденность:
;
существование эффективного алгоритма вычисления.
Как правило, в реализациях протокола используется спаривание Вейля.
Сравнение спариваний соответствует проверке следующего утверждения:
Итак, мы разобрались, как устроен PLONK. Далее речь пойдет про уязвимости протокола.
Некоторые известные уязвимости PLONK
Отсутствие маскирующих многочленов
Эта уязвимость приводит к нарушению свойства нулевого разглашения (см. доказательство соответствия селекторам), при этом эксплуатация ее на практике для подбора witness слишком вычислительно сложна для практического осуществления атаки.


Frozen Heart
Проверяющий не знает witness и не может непосредственно проверить соответствие ему всех компонентов доказательства. Пользуясь этим, нечестный доказывающий может выбрать случайные и вычислить соответствующие им коммитменты
, в конце каждого раунда добавляя их к доказательству и к transcript и получая псевдослучайные челленджи
. В случае если transcript не была инициализирована с помощью PI, доказывающий может вычислить PI уже после доказательства и осуществить подмену, если архитектура приложения этому благоприятствует (проверяющий принимает PI от доказывающего, как, например, было в snarkjs до исправления уязвимости):
Авторы этой статьи проанализировали 12 реализаций PLONK. В пяти была обнаружена уязвимость, в четырех из них она была исправлена к моменту публикации статьи. Для демонстрации атаки авторы выбрали Dusk Network — сохраняющий приватность распределенный ledger-протокол, использующий основанную на UTXO модель транзакций Phoenix, работающая с записями (notes), которые хранит ledger. Упрощенно, каждая запись является коммитментом для некоторого значения. Транзакция состоит из множества входных записей (in1, . . . , inm), множества новосформированных выходных записей (out1, . . . , outn) и доказательства корректности. Чтобы потратить запись, создатель транзакции должен раскрыть ее nullifier (идентификатор входа, позволяющий предотвратить двойное расходование), при этом не разглашая саму запись. В Dusk nullifier вычисляется как хеш индекса записи в дереве Меркла.
Секретным входом доказывающего (witness) являются входные записи, их openings, пути в дереве Меркла и openings для выходных записей. Целью доказательства является подтверждение того, что каждый nullifier соответствует валидной входной записи, каждая входная запись имеет валидный путь к корню дерева Меркла и выходные суммы равны входным.

Атака на слабое преобразование Фиата — Шамира позволила получить валидное доказательство для транзакции с выбранным произвольно nullifier (единственная проверка, которой подвергается эта переменная, — проверка того, что ранее то же значение не использовалось). Таким образом, атакующий мог переводить себе произвольные суммы с несуществующих входов.
00 bug
Критическая уязвимость в Aztec PLONK Verifier, обнаруженная вьетнамским исследователем по имени Нгуен Тхой Минь Куан, в результате которой любое доказательство принималось как валидное, если были равны точке на бесконечности O эллиптической кривой. Атака стала возможной благодаря сразу нескольким ошибкам в реализации проверки доказательства.
Проверяющий убеждается в том, что точки
лежат на кривой, но в противном случае его программа не прекращает работу мгновенно, как следовало бы, а исключает нулевые точки из некоторых последующих вычислений. Финальная проверка при этом все равно осуществляется;
В другом фрагменте кода, призванном исключить возможность того, что
является точкой на бесконечности, проверяется, что старший значащий бит точки не равен 1, но точка проходит проверку;
Для инверсии по модулю p используется метод, основанный на малой теореме Ферма. Так как входные данные не проверяются на корректность, обратным для 0 оказывается 0(p-2) = 0, что математически некорректно;
Перед проверкой спаривания Вейля осуществляется переход от проективных координат точек (x, y, z) к аффинным (z=1). В этих целях используется пакетная нормализация, в результате которой ненулевая точка
также становится нулевой под влиянием
, и финальная проверка сводится к
;
В завершение, если точка не лежит на кривой согласно первой проверке и не является точкой на бесконечности согласно второй, по логике verifier результат ее спаривания с любой точкой равняется 1.
Заключение
Хорошо исследованные криптографические протоколы не гарантируют безопасность продукта. Атаки на преобразование Фиата — Шамира показали, что ошибки реализации в современных zk-приложениях могут привести к нарушению свойства нулевого разглашения, создать возможность формирования валидного доказательства без обладания соответствующим знанием и в прикладном сценарии даже открыть путь к созданию неограниченного количества валюты. Более того, сама исходная спецификация PLONK потребовала исправления, чтобы корректно обеспечить заявленное свойство нулевого разглашения.
Поэтому, проверяя корректность работы zk-приложения, важно понимать, как свойства безопасности, доказанные для реализованного протокола, обеспечиваются на практике: как формируется transcript, как обрабатываются точки на бесконечности, как сохраняется секретность данных, которыми владеет доказывающий, и что произойдет, если участники протокола поведут себя не так, как предполагает спецификация.
Только при таком подходе доказательства с нулевым разглашением становятся частью безопасности продукта, а не иллюзией его криптографической надежности.
Полезные материалы по теме
Gabizon A., Williamson Z. J., Ciobotaru O.
PlonK: Permutations over Lagrange-bases for Oecumenical Noninteractive Arguments of Knowledge. — 2019. https://eprint.iacr.org/2019/953.pdf.
The Trail of Bits blog.
The Frozen Heart vulnerability in PlonK. — 2022. https://blog.trailofbits.com/2022/04/18/the-frozen-heart-vulnerability-in-plonk/.
Dusk.
PLONK Critical Vulnerability Successfully Remediated. — 2022. https://dusk.network/news/plonk-vulnerability-remediated.
Dao Q., Miller J. и др.
Weak Fiat-Shamir Attacks on Modern Proof Systems. — 2023. https://eprint.iacr.org/2023/691.pdf.
Sefranek M.
How to Simulate PLONK: A Formal Security Analysis of a zk-SNARK. — 2023. https://repositum.tuwien.at/bitstream/20.500.12708/188597/1/Sefranek%20Marek%20-%202023%20-%20How%20to%20Simulate%20PLONK%20A%20Formal%20Security%20Analysis%20of%20a...pdf.
Sefranek M.
How (Not) to Simulate PLONK. — 2024. https://eprint.iacr.org/2024/848.pdf.
Nguyen Q. T. M.
00: A Critical Vulnerability in Aztec PLONK Verifier. — 2021. https://eprint.iacr.org/2021/1638.0xPARC.
zk-bug-tracker: https://github.com/0xPARC/zk-bug-tracker.
Dusk Network.
Check the zero-knowledge property of PlonK. — GitHub issue #773. https://github.com/dusk-network/plonk/issues/773.The Risen Crypto blog. PlonK. https://risencrypto.github.io/Plonk/