Мультиподписи в сети Monero

Мы открываем цикл публикаций об устройстве различных блокчейнов и начнем исследования с монеро (Monero). Это достаточно известная криптовалюта, в ней реализован ряд интересных алгоритмических и криптографических решений. Несколько месяцев назад в Monero Core была добавлена поддержка мультиподписей, и в сегодняшней статье мы подробно рассмотрим эту технологию.

image


Мультиподписи — это механизм создания и использования кошельков общего доступа. Сама концепция не является новой, она уже реализована в некоторых криптовалютах, таких как Bitcoin, Ethereum и другие. Суть ее заключается в совместном владении и распоряжении средствами кошелька. На распоряжение средствами накладываются некоторые ограничения: для проведения транзакции необходимо набрать определенное количество голосов, которое задается при создании кошелька и зависит от числа его владельцев.

Эти параметры характеризуют так называемую «схему» кошелька, например, 3 / 3 — кошелек на троих владельцев с необходимыми тремя подписями для отправки транзакции, или 2 / 3 — кошелек на троих владельцев с необходимыми двумя подписями любых его владельцев. Следует отметить, что в мультисиг-кошельках (multisignature wallet) нет понятия «твоя доля» и «моя доля», все средства принадлежат всем участникам одновременно.

Криптография в Monero


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

Каждый кошелек в сети монеро имеет две пары (приватных и публичных) ключей — view и spend. Пара публичных ключей view и spend называется адресом кошелька. Его вы можете использовать в качестве адреса для получения средств. Если вы хотите предоставить информацию о количестве и размере поступлений на ваш кошелек третьим лицам, то можете, помимо адреса, предоставить еще приватный view ключ. Пара приватного view ключа и публичного spend называется tracking ключом. С его помощью можно видеть поступления средств на кошелек (но не расходы) и это абсолютно безопасно — владеющий такой парой ключей не сможет потратить ваши средства.
Пожалуй, самым секретным ключом является приватный spend — им нельзя делиться ни с кем, т.к. владея им и приватным view ключом можно распоряжаться средствами кошелька.

Далее в статье публичные ключи мы будем обозначать заглавными буквами (например, B — публичный spend ключ), а приватные — строчными (b — приватный spend ключ). Для понимания некоторых выкладок ниже в статье покажем, как публичный ключ наследуется от приватного:

Формула: Наследование публичного ключа. B = bG


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

Мультиподписи в сети Monero


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

Разумеется, ни в какой момент времени ни один из участников не может собрать весь ключ целиком. Публичный же spend ключ хранится целиком у каждого участника. Также каждый из участников хранит полную версию приватного и публичного view ключа, что вкупе с публичным spend-ом позволяет видеть входящие поступления на общий адрес.

Создание мультисиг-кошелька в Monero


Текущая релизная версия Monero поддерживает лишь схемы N / N и N — 1 / N.

Процесс создания происходит в 1 или 2 этапа для схем N / N и N — 1 / N соответственно. На первом этапе участники процесса обмениваются друг с другом приватными view и публичными spend ключами и вычисляют суммы этих ключей — всех view и всех spend. Таким образом, приватным view ключом кошелька становится сумма view ключей для всех схем, а публичным spend ключом для схемы N / N — сумма публичных spend ключей всех участников. На этом генерация N / N кошелька заканчивается.

Для N — 1 / N кошельков появляется еще один набор ключей. Этот набор представляет собой массив приватных ключей, вычисленный как произведение своего текущего приватного spend ключа на каждый из публичных spend ключей других участников, то есть (без учета функции хэширования для простоты):

Формула: Вычисление multisig ключей


И аналогично для каждого из участников.
cut/>

Приватным spend ключом каждого из участников будет сумма его multisig ключей, то есть:

image


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

image


Из этого равенства следует вывод, что каждый кошелек имеет у себя один (в нашем примере со схемой 2/3) multisig ключ, который есть у другого участника.

После генерации участники обмениваются публичными multisig ключами:

Формула: Вычисление публичного multisig ключа


В финале вычисляется публичный spend ключ кошелька суммированием уникальных значений публичных multisig ключей, то есть для нашего примера это будет:

Формула: Вычисление публичного spend ключа


Как мы видим, для вычисления spend ключа (как приватного, так и публичного) в случае 2 / 3 нам достаточно информации от любых двух участников.

На этом создание кошелька завершается, и его можно использовать в соответствии с выбранной схемой.

Транзакции в Monero


Чтобы объяснить, как создаются мультисиг-транзакции, коротко рассмотрим, как устроена транзакция в Monero. Упрощенно (без кольцевых подписей и RingCT) ее можно представить себе так:

Упрощенное представление транзакции


Рисунок 1. Упрощенное представление транзакции

Здесь справа изображены выходы транзакции — деньги, которые она генерирует (прямая аналогия: купюры в кошельке), а слева входы — деньги, которые она сжигает.

Таким образом, когда Алиса хочет отправить Бобу 1 XMR, она набирает среди своих непотраченных выходов сумму в 1 XMR плюс комиссия, помещает их на место входов транзакции, вычисляет для каждого из них key image, формирует выходы на сумму 1 XMR и вычисляет для каждого из них output key.

После получения транзакции Боб для каждого из выходов восстанавливает output key, используя приватный view и публичный spend ключи, и, если восстановленный и пришедший в транзакции ключи совпадают, считает этот выход предназначенным ему.

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

  • Участники обмениваются частичными key image-ами для известных выходов (или просто обмен выходами)
  • Участники пересинхронизируют свои кошельки с целью получить точный баланс с учетом уже полных key image-ей
  • Отправитель готовит транзакцию, подписывает ее и отправляет следующему участнику
  • Каждый последующий участник добавляет свою часть RingCT подписи
  • Последний подписывающий завершает создание RingCT


И теперь транзакция готова к отправке в сеть.

Генерация key image и обмен выходами


В ходе сканирования блокчейна (синхронизации) кошелек не может определить, что конкретные входы тратят именно его выходы, так как у него нет возможности вычислить key image для них. Поэтому он видит только входящие транзакции (для них достаточно только пары tracking key).

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

Рассмотрим процесс формирования key image. Вычисляется он по формуле:

Формула: Формирование key image


, где Hp — некая заранее заданная хэш-функция, P — публичный ключ выхода (см. рисунок 1), x — приватный ключ выхода, который восстановим для получателя этого выхода, вычисляется он следующим образом:

Формула: Восстановление приватного ключа выхода


, где Hs — некая заранее известная криптографическая хэш-функция, a — приватный view ключ, R — публичный ключ транзакции (Tx pub key, см. рисунок 1) и b — приватный spend ключ. Подставив одно выражение в другое и раскрыв скобки, мы получаем:

Формула: Вычисление key image


Но так как мы не имеем цельного spend ключа, необходимо его восстановить. В случае N / N все просто (возьмем для примера 3 / 3):

Формула: Восстановление key image для N / N


Здесь Hp (P)bi — частичный key image, получаемый от i-го участника.

Для схем N — 1 / N (2 / 3 от лица первого участника без участия третьего):

Формула: Восстановление key image для N - 1 / N


в данном случае Hp (P)biBj — частичный key image.

Суть процесса обмена выходами как раз и заключается в том, чтобы необходимое число подписывающих транзакцию отправило свои частичные key image для каждого из выходов другим участникам кошелька. При этом участники не раскрывают своих приватных ключей, таким образом у стороннего наблюдателя или недобросовестного участника нет возможности восстановить полный spend ключ и завладеть кошельком единолично.

Располагая этими данными, инициатор транзакции может сформировать ее и подготовить к подписи. Сформированная транзакция рассылается всем согласным ее подписать для генерации Ring CT подписи, создаются все необходимые подписи и транзакция отправляется в сеть.

Автоматизация обмена данными


Выше описаны процедуры для обмена частями ключей и key image-ми, которые нужно проводить либо один раз, либо после каждой отправленной транзакции. В текущей реализации Monero Core Wallet эти действия предлагается выполнять вручную путем обмена нужными данными по защищенным каналам связи со своими корреспондентами вручную (экспортируя нужные данные из кошелька и пересылая их через мессенджеры или иным способом).

Продемонстрировать это можно на примере создания кошелька по схеме 2 / 3 и подписи транзакции. Каждый из участников выполняет следующие команды при помощи утилиты monero-wallet-cli:

[wallet 9uKCgo]: prepare_multisig
MultisigV1baCWviNomMXe271W8HW4imh8SsnNEWP2bCswQfoB9MGzNZ8FUG3e8UCNm5toKQzSQH2e8rUWUCGazaCcvej1ToCQYBMovJZYaYiYWQvzsvyWruXycZdVDSsyugjEzwQNK3FUEkug2LXiH91NmekGb7kp9gK9kuoxDDhGn1nLKXUpnXR5
Send this multisig info to all other participants, then use make_multisig   [...] with others' multisig info
This includes the PRIVATE view key, so needs to be disclosed only to that multisig wallet's participants 

[wallet 9uKCgo]: make_multisig 2 MultisigV1XQugvU4JwcwTQbKdH5qGFnavxUX54wGxNis2iN6zoLD94DahnXbyNxH1NQBp2rYRFFJCT2uiJbssHLJYEAb8X1tS5UCqTXYu3FkgRNSZt5mRNgE58iXZHPj839Pbm3ozGcXmRT6GcRMMxMjRonfYKpnPq1UyZSMN7Qr9AYin1gYyoJSh MultisigV1HVqTW8P4UNWUE8QfBaEdwDWJuXBWEPnTrKqVJiUudGG14cHREk9TKmeR9xzSs4wf4jd22mV94C2ehSViApawnpp2SpRqp19eKXLHz2JmNp7eGR6TJMt4VsDTqANRwb1FtD9weef342f5KXDRZK7iQT1MTubyHhEcFyV5aLCjjQ8owMkH
Another step is needed
MultisigxV1PQwytRuYGkB6UEVJ7v2S7q492cwNTdwySXyasToAuQQq73TvM1rBrog5bcYz5w2P6Z4jwKtzrHr7shRGo5mAShvLVbYtBdQNhQsizMb51K7iaWQB4te5mQaiB1cok84CbvA9WKnVpTJGyb7SbS7NwAgmpEhU812RTdzrdHp5sD41duYtRNW6qna5mTMYmtTjAEdKpKCvM6EwhV4ncWscpvoBfyYP
Send this multisig info to all other participants, then use finalize_multisig  [...] with others' multisig info

[wallet 9uKCgo]: finalize_multisig MultisigxV1PdeMJo5rxcWTXDJ7rbyuacBseugsn2djZKKEdwvFYVmz73TvM1rBrog5bcYz5w2P6Z4jwKtzrHr7shRGo5mAShvLUxykuq5gho7gGQBCEa3JmBaY7rNHqqUaCUs1WWQi9tojZTMmCJJ4evwJzcXEDqcAd7ShwxsJtJtXdiATs54BbBfyCbwXbnDRKAtagJF36z74KJA58NgEmnHv23ZQeePCoacM MultisigxV1RTwyE53FjKPQaAn4ZMWM5hc8C92eJndpyKby4L9HpF2TUxykuq5gho7gGQBCEa3JmBaY7rNHqqUaCUs1WWQi9tojVbYtBdQNhQsizMb51K7iaWQB4te5mQaiB1cok84CbvA928U2yJFK86jNxtMopxHkcnYjjeYfp8TAB53Y1CukBiHfL2M4EztDALXLReXjJxkMry65Jw6vVePJp2T5CW8T8QE5


Перед отправкой транзакции стороны должны обменяться частичными key image-ами:

[wallet 9uKCgo]: export_multisig_info ki1
Multisig info exported to ki1
[wallet 9uKCgo]: import_multisig_info ki2 ki3
Height 1103873, txid , 2.000000000000, idx 0/0
Height 1103882, txid <2e3a5591c741c0943a47a2bcbd1ec26493158088c88308bcbfc97423ea95c491>, 0.009000000000, idx 0/0
Multisig info imported


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

[wallet 9uKCgo]: transfer 9vUnTucAioDHD4ZqrFHXAgfLqrsC3LkZ6JFr5axBLhDiFMaHuEk33aqXimoZEMtQh5ibdYxcNSBw2hBZLAsCnuw4B4rBeZX 1
No payment id is included with this transaction. Is this okay?  (Y/Yes/N/No): Y
There is currently a 2 block backlog at that fee level. Is this okay?  (Y/Yes/N/No)Y

Transaction 1/1:
Spending from address index 0
Sending 1.000000000000.  The transaction fee is 0.012000000000
Is this okay?  (Y/Yes/N/No): Y
Unsigned transaction(s) successfully written to file: multisig_monero_tx


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

[wallet 9twQxU]: sign_multisig multisig_monero_tx
Loaded 1 transactions, for 1.031762770000, fee 0.012000000000, sending 1.000000000000 to 9vUnTucAioDHD4ZqrFHXAgfLqrsC3LkZ6JFr5axBLhDiFMaHuEk33aqXimoZEMtQh5ibdYxcNSBw2hBZLAsCnuw4B4rBeZX, 0.019762770000 change to 9uKCgopHzXrQLnph1ZNFQgdxZZyGhKRLfaNv7EEgWc1f3LQPSZR7BP4ZZn4oH7kAbX3kCd4oDYHg6hE541rQTKtHB7ufnmk, with min ring size 7, no payment ID. Is this okay? (Y/Yes/N/No): Y
Transaction successfully signed to file multisig_monero_tx, txid 1d28af64bc78d05b625c4f7af7c321d4c8943c4c2692f57aa53e303387f40db6
[wallet 9twQxU]: submit_multisig multisig_monero_tx
Loaded 1 transactions, for 1.031762770000, fee 0.012000000000, sending 1.000000000000 to 9vUnTucAioDHD4ZqrFHXAgfLqrsC3LkZ6JFr5axBLhDiFMaHuEk33aqXimoZEMtQh5ibdYxcNSBw2hBZLAsCnuw4B4rBeZX, 0.019762770000 change to 9uKCgopHzXrQLnph1ZNFQgdxZZyGhKRLfaNv7EEgWc1f3LQPSZR7BP4ZZn4oH7kAbX3kCd4oDYHg6hE541rQTKtHB7ufnmk, with min ring size 7, no payment ID. Is this okay? (Y/Yes/N/No): Y
Transaction successfully submitted, transaction <1d28af64bc78d05b625c4f7af7c321d4c8943c4c2692f57aa53e303387f40db6>
You can check its status by using the `show_transfers` command.


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

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

Более подробно об этом проекте можно узнать на странице wallet.exan.tech, а о ресурсах, которые мы поддерживаем для сети Monero — в разделе exan.tech/en/projects/monero.

Заключение


Мы рассмотрели механизм создания мультисиг-кошельков и формирования транзакций с мультиподписями в Monero. На текущий момент поддерживается только ограниченный набор схем подписи, но он будет расширен до произвольных формул вида 2 / 5 и т.п. Существующий механизм обмена данными, необходимыми для функционирования кошелька, довольно неудобен, но благодаря открытости экосистемы Monero с помощью сторонних решений он может быть доведен до привычного обычным пользователям качества.

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

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

© Habrahabr.ru