Готовясь к активации Taproot

0
ПОДЕЛИТЬСЯ

Перевод серии постов от Bitcoin Optech, посвященных технической стороне подготовки к активации Taproot. Рекомендации, примеры кода, ссылки на обучающие материалы и просто чего ожидать при активации. А также ожидаемые новые функции и предположительные сроки их реализации.

Список тем:

Поддержка отправки bech32m

Начиная с блока 709 632 пользователи Биткойна смогут безопасно получать платежи на taproot-адреса. Учитывая уровень энтузиазма пользователей по поводу обновления Taproot и пять месяцев, которые были у разработчиков кошельков, чтобы реализовать его поддержку, мы ожидаем, что как минимум несколько популярных кошельков позволят своим пользователям генерировать taproot-адреса если не с самого момента активации, то в кратчайшие возможные сроки.

Это означает, что в идеале к 709 632 блоку любой другой кошелек или сервис, отправляющий биткойны на пользовательские адреса, должен позволять отправку на taproot-адреса. Иначе он рискует запутать и разочаровать своих пользователей. Pay-to-Taproot (P2TR) адреса, согласно спецификациям BIP350, используют схему кодирования bech32m, несколько отличающуюся от bech32 алгоритма BIP173, используемого в segwit v0 для P2WPKH и P2WSH адресов. Bech32m использует в функции контрольной суммы константу 0x2bc830a3 вместо 0x01, используемой в bech32.

Изменение этой единственной константы обеспечивает возможность проверки контрольных сумм bech32m, но коду все равно необходимо использовать исходную константу для существующих P2WPKH и P2WSH адресов. Код должен декодировать адрес без проверки контрольной суммы, определить, используется ли в нем segwit v0 (bech32) или segwit v1+ (bech32m), а затем проверить контрольную сумму с помощью соответствующей константы. Примеры см. в пулл-реквесте с обновлением эталонных реализаций bech32 для C, C++, JS и Python. Если код уже использует справочные библиотеки, их можно обновить до последней версии из этого репозитория, только обратите внимание на небольшие изменения в некоторых API. BIP350 и эталонные реализации включают в себя тест-векторы, которые следует использовать во всех реализациях bech32m.

Хотя получение платежей на taproot-адреса до блока 709 632 небезопасно, отправка не должна вызывать у отправителя никаких проблем. Bitcoin Core поддерживает ретранслирующие и майнинговые транзакции с taproot-выходами с версии 0.19 (выпущена в ноябре 2019).

Имеет ли смысл использовать taproot для обычных транзакций с одной подписью?

С помощью калькулятора размера транзакций от Bitcoin Optech можно сравнить по размеру различные типы транзакций с одной подписью (single-sig). Как можно было ожидать, транзакции с P2WPKH входами и выходами намного меньше транзакций с P2PKH входами и выходами, однако — и это может удивлять — P2TR транзакции несколько больше эквивалентных P2WPKH транзакций.

  P2PKH (legacy) P2WPKH (segwit v0) P2TR (taproot/segwit v1)
Output 34 31 43
Input 148 68 57.5
2-in, 2-out tx 374 208.5 211.5

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

  • Дешевле тратить: на уровне входа транзакции расходование single-sig P2TR UTXO обходится на 15% дешевле, чем P2WPKH UTXO. В простейшем анализе, как в таблице выше, не раскрывается такой нюанс, что отправитель транзакции не выбирает, на какой адрес ему предлагается произвести оплату, так что если вы останетесь на P2WPKH, а все остальные перейдут на P2TR, фактический типичный размер ваших 2-in-2-out транзакций составит 232,5 vБайт, тогда как размер транзакций с P2TR на всех входах и выходах по-прежнему будет составлять только 211,5 vБайт.
  • Приватность: хотя обычно переход на новый формат скриптов для ранних пользователей подразумевает некоторую потерю в приватности, при переключении на taproot пользователи получают немедленное повышение уровня приватности. Ваши транзакции смогут выглядеть неотличимо от транзакций в новых lightning-каналах, обеспечат более эффективные DLC, более безопасные мультиподписи, различные «умные» схемы восстановления доступа к средствам и возможности для сотен других новаторских разработок.Использование P2TR для single-sig транзакций позволяет кошельку также реализовать поддержку мультиподписей, Tapscript, Lightning Network или других функций без ущерба для конфиденциальности существующих пользователей. Не имеет значения, был ли UTXO получен в старой или в новой версии вашего ПО — оба UTXO ончейн будут выглядеть одинаково.
  • Удобнее для [аппаратных] устройств электронной подписи: после нового «открытия» атаки переплатой комиссии (fee overpayment attack), несколько аппаратных средств ЭП отказались подписывать транзакции, если только каждый расходуемый в ней UTXO не сопровождается метаданными, содержащими копию значительной части транзакции, в которой этот UTXO был создан. Это значительно увеличивает объем worst-case обработки, выполняемую подписывающими устройствами в наихудшем сценарии, что особенно проблематично для устройств ЭП, использующих в качестве основного канала связи QR-коды ограниченного размера. Taproot устраняет уязвимость, лежащую в основе атаки переплатой комиссии, и, следовательно, может значительно повысить производительность устройств ЭП.
  • Более предсказуемые ставки комиссии: размер ECDSA-подписей для P2PKH и P2WPKH UTXO может варьироваться. Поскольку ставку комиссии за транзакцию кошелькам нужно выбрать до создания подписи, большинство кошельков просто исходят из наибольшего возможного размера подписи и соглашаются с небольшой переплатой, если сгенерированная подпись окажется меньшего размера. Для P2TR точный размер подписи известен заранее, что позволяет кошельку надежно выбрать точную ставку комиссии.
  • Помощь полным узлам: безопасность системы Биткойна во многом строится на том, что значительная часть пользователей проверяет каждую подтвержденную сетью транзакцию с помощью собственных полных нод. Используемые в taproot подписи Шнорра допускают эффективную пакетную проверку, что примерно вполовину сокращает количество циклов процессора, затрачиваемых нодой при проверке подписей в процессе восполнения и обработки предыдущих блоков. Даже если все остальные пункты в этом списке не вызвали у вас интереса, рассмотрите возможность поддержки taproot, чтобы несколько упростить для пользователей Биткойна поддержку полных узлов.

Taproot дескрипторы

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

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

Прежде чем это произойдет, дескрипторы необходимо обновить для работы с taproot. Это стало предметом пулл-реквеста #22051 в Bitcoin Core. Синтаксис разработан таким образом, чтобы вместить в один шаблон дескриптора всю необходимую информацию для расходования как по P2TR keypath, так и по scriptpath. Для простой single-sig транзакции достаточно такого дескриптора:

tr(<key>)

Тот же синтаксис можно использовать и для мультиподписей и пороговых (threshold) подписей. Например, Элис, Боб и Кэрол объединяют свои ключи с помощью MuSig, а затем делают выплату на tr(<combined_key>).

Несколько контринтуитивно, но ключ, указанный в tr(<key>), не будет ключом, закодированным в адрес. Дескриптор tr() следует рекомендации по безопасности из BIP341 использовать внутренний ключ, который фиксируется в дереве нерасходуемого скрипта. Это исключает атаку на пользователей наивных схем агрегирования ключей (более продвинутые схемы, такие как MuSig и MuSig2, таким атакам не подвержены).

Для расхода по scriptpath добавлен новый синтаксис, позволяющий указывать содержимое двоичного дерева. Например, { {B,C} , {D,E} } описывает следующее дерево:

Internal key
    / \
   /   \
  / \ / \
  B C D E

Дерево может быть указано в качестве необязательного второго параметра шаблона дескриптора, который мы использовали ранее. Например, если Элис хочет потратить биткойны по keypath, но также хочет позволить Бобу, Кэрол, Дэну и Эдмонду расходование через scriptpath, который генерирует для нее (но не для стороннего наблюдателя) путь аудита, Элис может использовать следующий дескриптор:

tr( <a_key> , { {pk(<b_key>),pk(<c_key>)} , {pk(<d_key>),pk(<e_key>)} )

Вышеописанные опции — это всё, что требуется для использования дескрипторов для taproot, однако в пулл-реквесте #22051 перечисляется также ряд отсутствующих опций, которые можно было бы добавить, чтобы дескрипторы лучше и полнее описывали ожидаемые пользовательские политики расходования:

  • Аннулирование keypath: некоторые пользователи могут захотеть запретить расходование по keypath, оставив только вариант scriptpath. Сейчас это можно сделать, используя в качестве первого параметра tr() нерасходуемый ключ, но хорошо было бы позволить кошелькам хранить это предпочтение в самом дескрипторе и вычислять нерасходуемый keypath без ущерба для приватности.
  • Tapscript multisig: для legacy и segwit v0 стандартов, дескрипторы multi() и sortedmulti() поддерживают опкод OP_CHECKMULTISIG. Чтобы позволить выполнение пакетной проверки в taproot, мультиподписи на основе скриптов в tapscript обрабатываются несколько иначе, поэтому на сегодняшний день дескрипторам tr() приходится указывать любые необходимые multisig опкоды через скрипт raw(). Было бы неплохо заручиться обновленными версиями скриптов multi() и sortedmulti() для tapscript.
  • Мультиподписи на основе MuSig: в примере выше мы описывали, как Элис, Боб и Кэрол вручную агрегировали свои ключи, чтобы использовать дескриптор tr(). В идеале хорошо было бы иметь функцию, которая позволила бы им указать что-то вроде tr(musig(<a_key>, <b_key>, <c_key>)), чтобы они могли сохранить всю информацию об исходном ключе и использовать ее для заполнения полей в PSBT, используемых для координации подписания.
  • Timelock, hashlock и pointlock:блокировка по времени, по хешу и по точке на эллиптической кривой — эти мощные конструкции, используемые в Lightning Network, DLC, CoinSwap и многих других протоколах, в настоящее время могут быть описаны только с помощью функции raw(). Добавление их поддержки непосредственно в дескрипторы возможно, но может случиться так, что вместо этого поддержка будет реализована через родственный дескрипторам проект miniscript. Интеграция miniscript в Bitcoin Core еще в процессе, но мы ожидаем, что в будущем эти инновации распространятся и на другие кошельки, как это уже произошло с PSBT и дескрипторами.

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

От P2WPKH к single-sig P2TR

Для кошельков, уже поддерживающих получение и расходование P2WPKH-выходов segwit v0, обновление до segwit v1 P2TR для single-sig транзакций должно быть довольно простым. Основные шаги выглядят так:

  • Используйте новый путь вывода (деривации) ключа: вам не нужно изменять свой BIP32 иерархический детерминированный (HD) код и пользователям не нужно генерировать новые seed-значения.[1] Тем не менее настоятельно рекомендуется использовать новый путь вывода для открытых P2TR ключей (как это определено в BIP86). Игнорирование этой рекомендации открывает возможности для атаки, и они могут быть реализованы, если вы используете одни и те же ключи для ECDSA и для подписей Шнорра.
  • Настройте свой открытый ключ по его хешу: хотя технически для single-sig это не требуется, особенно если все ваши ключи получены из случайным образом сгенерированного BIP32 seed-значения, BIP341 рекомендует зафиксировать ключ в нерасходуемое scripthash дерево. Это не сложнее операции сложения эллиптической кривой, суммирующей открытый ключ с точкой на кривой, соответствующей хешу этого ключа. Соблюдение этой рекомендации позволит вам использовать тот же код при добавлении поддержки дескрипторов tr() или если позже вы решите добавить поддержку scriptless мультиподписей (Scriptless Scripts PDF).
  • Создайте адреса и отслеживайте их: для создания адресов используйте bech32m. Платежи будут отправляться на scriptPubKey OP_1 <tweaked_pubkey>. Сканировать транзакции в адрес скрипта можно любым методом, который вы использовали для сканирования segwit v0 адресов, как P2WPKH.
  • Создание расходной транзакции: все поля, кроме witness, для taproot такие же, как для P2WPKH, поэтому об изменениях в сериализации транзакций можно не беспокоиться.
  • Создайте сообщение подписи: это фиксация, коммитмент, данных из транзакции расходования. Большая часть данных совпадает с тем, что подписывается для P2WPKH-транзакции, но изменяется порядок полей, плюс подписывается несколько дополнительных элементов. Реализация этого, по сути, сводится к сериализации и хешированию различных данных, так что код написать должно быть несложно.
  • Подпишите хеш сообщения подписи: есть разные способы создания подписей Шнорра. Лучше не изобретать велосипед, а использовать функцию из проверенной библиотеки, которой вы доверяете. Но если по какой-то причине вы не можете этого сделать, BIP340 предоставляет алгоритм, который должно быть довольно просто реализовать, имея необходимые примитивы для создания ECDSA подписей. Получив подпись, внесите ее в witness-данные для своего входа и отправьте транзакцию.

До активации taproot на 709 632 блоке код можно протестировать в тестовой сети, публичной дефолтной signet или в приватном regtest режиме Bitcoin Core. При добавлении поддержки taproot в кошелек с открытым исходным кодом, мы рекомендуем делиться ссылками на соответствующие пулл-реквесты на Taproot Uses и Bech32 adoption страницах Bitcoin Wiki, чтобы другие разработчики могли учиться на примере вашего кода.

Сохранность средств на P2TR выходах до активации и безопасный период после активации taproot

Реализовывать поддержку taproot в кошельках и сервисах вполне уместно и правильно заранее, чтобы к блоку активации все было уже готово. Но не следует генерировать какие бы то ни было адреса для P2TR до блока 709 632, поскольку это может привести к потере денег сервисом и его пользователями.

Причина заключается в том, что до блока 709 632 любые средства, отправленные на P2TR выход, могут быть потрачены кем угодно. Деньги будут в этом случае будут абсолютно не защищены. Но начиная с блока активации тысячи полных узлов начнут применять правила BIP341 и BIP342 (и заодно BIP340).

Если бы была 100% гарантия того, что реорганизации блокчейна не произойдет, то было бы безопасно начать генерировать адреса для P2TR сразу же с момента появления последнего блока перед taproot (709 631). Но есть причина для беспокойства насчет возможных реорганизаций — не только случайных, но и специально направленных на получение денег от преждевременных платежей на P2TR.

Представьте себе большое количество людей, которые хотят быть в числе первых, кто получит P2TR платеж. Они наивно отправляют сами себе небольшую сумму, как только видят блок 709 631.[2] Эти платежи будут защищены в блоке 709 632, однако они могут быть беспрепятственно украдены любым майнером, который создаст альтернативу блоку 709 631. Если общая стоимость отправленных на P2TR биткойнов достаточно велика, то может быть оправдано попытаться добыть два блока вместо одного (подробнее в теме Fee Sniping на Bitcoin Optech).

По этой причине мы не рекомендуем генерировать адреса для P2TR до того момента, как вы будете уверены, что риск реорганизации больше неактуален. Мы считаем период в 144 блока (около одного дня) после активации достаточно консервативным, чтобы свести риски к минимуму, не задерживая чрезмерно сервисы и пользователей от использования taproot.

В двух словах:

  • 709 631: последний блок, в котором кто угодно может потратить средства, отправленные на P2TR-выход.
  • 709 632: первый блок, в котором P2TR могут быть потрачены, только если они отвечают правилам BIP341 и BIP342.
  • 709 776: окончание разумно безопасного периода ожидания, начиная с которого кошельки и сервисы могут предоставлять своим пользователям bech32m адреса для получения P2TR выходов.

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

Изучайте taproot, используя его

Около двух лет назад James Chiang и Elichai Turkel создали открытый репозиторий Jupyter-документов для серии воркшопов Bitcoin Optech, посвященных обучению разработчиков технологии taproot. Воркшопы в Сан-Франциско, Нью-Йорке и Лондоне, получили положительные отзывы, но возникшие позже ограничения на поездки помешали проведению новых очных семинаров.

С момента публикации этих Jupyter-документов taproot претерпел несколько изменений. Но вместе с тем поддержка taproot была добавлена в Bitcoin Core, что позволило репозиторию устранить зависимость от отдельной кастомной ветки Bitcoin Core. Разработчик Elle Mouton любезно обновил репозиторий с учетом всех этих изменений, снова превратив его в отличный способ быстро получить практический опыт работы с taproot алгоритмами и типами данных.

Документы репозитория поделены на четыре раздела:

  • Раздел 0 поможет вам настроить свое окружение, расскажет об основах эллиптической криптографии и о тегированных хешах, используемых в BIP 340, 341 и 342.
  • Раздел 1 проведет через процесс создания подписей Шнорра. Освоив это, вы узнаете, как создавать мультиподписи с помощью протокола MuSig.
  • Раздел 2 дает опыт работы со всеми аспектами taproot. Он начинается с принципов действия транзакций segwit v0, а затем помогает создать и отправить первые транзакции segwit v1 (taproot). Применив знания из раздела 1, вы сможете создать и отправить taproot-выход с помощью MuSig. Здесь вводится концепция настройки ключа, и вы узнаете, как taproot позволяет использовать открытый ключ для фиксации данных. Теперь, когда вы можете создавать коммитменты, вы узнаете о tapscript(ах) — чем они отличаются от исходных (legacy) скриптов Биткойна и от segwit v0 скриптов и как выполнять привязку к дереву tapscript(ов). Наконец, последний короткий файл знакомит с кодированием Хаффмана для создания оптимальных деревьев скриптов.
  • В разделе 3 представлено дополнительное упражнение по созданию taproot-выхода, который изменяет требования к подписям по мере того, как выход остается неизрасходованным, что позволяет эффективно расходовать выход в обычных обстоятельствах, но также обеспечивает надежный способ восстановления доступа к средствам в случае проблем.

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

Обзор мультиподписи

В последней 1000 блоков по состоянию на момент написания этой части 11% всех входов транзакций содержали опкод мультиподписи. Два самых больших и непосредственных преимущества taproot проявятся, если многие из пользователей и сервисов, создающих такие транзакции, перейдут с опкодов на scriptless мультиподписи.

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

Готовясь к активации Taproot

Второе важное преимущество — это повышение приватности. Каждое использование multisig скрипта явным и определенным образом записывается в блокчейн, где наблюдатели могут использовать эти записи для формулирования обоснованных предположений об истории кошелька и текущем балансе отдельных пользователей. Например, глядя на блок 692 039, мы можем не только отличить multisig и single-sig транзакции друг от друга, но и сделать некоторые обоснованные выводы на основе размеров сетов и пороговых значений для multisig скриптов.

Готовясь к активации Taproot

Для сравнения, третья сторона на основе только данных блокчейна не может сделать вывод о том, что отправитель использовал мультиподпись. Когда для расходования по keypath используется мультиподпись, это неотличимо от расходования через single-sig транзакции. Если все single-sig и multisig транзакции в блоке выше перевести в P2TR транзакции расхода по keypath, то различимы за счет своих скриптов будут лишь несколько экзотических расходований (и те в самом идеальном сценарии могли быть реализованы через keypath).

Готовясь к активации Taproot

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

Нам известно о трех схемах мультиподписи на основе схемы Шнорра, разработанных специально для Биткойна, все из семейства MuSig:

  • MuSig (называемая также MuSig1), довольно простая в реализации, но для которой требуется три раунда коммуникации в процессе подписания.
  • MuSig2, тоже простая в реализации. Исключает один раунд коммуникации и позволяет объединить еще один раунд с обменом ключами. Это позволяет использовать процесс подписания, в чем-то схожий с тем, что мы используем сегодня с мультиподписями на основе скриптов. Это требует хранения дополнительных данных и большой осторожности в отношении того, чтобы ваше ПО или устройство нельзя было обмануть, заставив его повторно воспроизвести часть сеанса подписания. Подробнее возникающие компромиссы мы рассмотрим в следующем разделе.
  • MuSig-DN (Deterministic Nonce), значительно более сложная в реализации. Коммуникацию между участниками здесь нельзя объединить с обменом ключами, но зато эта схема неуязвима для атаки повтора сессии.

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

Существует открытый и активно разрабатываемый пулл-реквест к проекту libsecp256k1-zkp для добавления поддержки MuSig2. Мы ожидаем, что базовый процесс работы с мультиподписью для большинства программ будет выглядеть примерно следующим образом:

  1. Кошелек каждого участника генерирует BIP32 xpub, которым они делятся с остальными участниками с помощью дескриптора скрипта выхода или иного метода (аналогично тому, как это обычно реализуется сейчас для скриптов мультиподписи).
  2. Затем любой из кошельков может сгенерировать общий, агрегированный открытый ключ, объединив свой pubkey на определенной BIP32 глубине с pubkey на той же глубине от всех остальных кошельков множества мультиподписи. Этот агрегированный открытый ключ можно использовать для получения P2TR платежей.
  3. Когда один из кошельков хочет потратить средства, он использует процесс на основе PSBT, подобный тому, что использовал бы со скриптовой мультиподписью, но теперь требуется два раунда коммуникаций между подписывающими сторонами. В первом раунде инициатор создает неподписанную транзакцию и включает в нее пару случайным образом сгенерированных nonce. Абсолютно важно, чтобы значения nonce не были получены полностью детерминированным способом, который бы мог привести к повторному использованию того же nonce для другой подписи. Инициатор отправляет PSBT с двумя nonce другим кошелькам.
  4. Другие кошельки получают PSBT, добавляют в нее свои пары случайных nonce и отправляют другим кошелькам или общему координатору, бездоверительным образом работающему от имени кошельков.
  5. Когда все кошельки получают все пары nonce, они объединяют их в одно nonce значение. Опять же, координатор может сделать это за подписантов. Затем все кошельки добавляют в свои версии PSBT частичные подписи и отправляют PSBT остальным кошелькам либо координатору. После этого частичные подписи объединяются для создания окончательной подписи и транзакция транслируется.

Пороговые подписи

Само по себе семейство схем мультиподписей MuSig позволяет создавать только n-of-n подписи — каждая сторона, предоставляющая свой ключ для сводного открытого ключа, должна также внести частичную подпись для создания общей окончательной. Это прекрасно работает как прямая замена для некоторых видов использования сегодняшних скриптов мультиподписи — таких как расходование 2-из-2 выходов финансирования Lightning Network, — но является отклонением от других популярных политик, таких как скрипт мультиподписи 2-из-3, используемый многими биржами.

Несколько разработчиков работают схемами пороговой подписи (threshold signature), которые бы обеспечили сценариям k-of-n те же преимущества эффективности и приватности, что и мультиподписи, но до тех пор, пока они еще не доступны, можно использовать простой трюк.

Во многих случаях применения пороговых схем заранее известно, какие участники с наибольшей вероятностью предоставят свою подпись. Например, в ситуации 2-из-3 может быть известно, что обычно Элис и Боб совместно подписывают транзакции, в то время как Кэрол предоставляет подпись, только если один из прочих участников недоступен. В этих обстоятельствах первичные ключи могут использовать мультиподпись для taproot-расхода по keypath (например, между Элис и Бобом), а дополнительные выходы (Элис и Кэрол или Боб и Кэрол) могут использовать мультиподписи с опкодом OP_CHECKSIG в отдельных ветвях дерева tapscript(ов).

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

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

Nonce-значения мультиподписи

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

Чтобы подтвердить подпись в Биткойне, вы заполняете общеизвестное уравнение подписью, подписанным сообщением (например, транзакцией), своим открытым ключом и открытым nonce. Уравновесить это уравнение можно только в том случае, если вы знаете свой закрытый ключ и закрытую форму nonce. Так любой, кто видит подобное сбалансированное уравнение, может заключить, что это сообщение и открытый ключ валидны.

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

Nonce-значения в этом контексте — это не просто числа, используемые один раз, но числа, которые должны использоваться строго один раз. Если вы используете один и тот же nonce в двух разных подписях, эти два уравнения подписи можно объединить в одно, nonce из него вывести, и, опять же, вычислить единственное оставшееся неизвестное — закрытый ключ. Если вы используете простую (non-hardened) деривацию стандарта BIP32, что, вероятно, предпочтут практически все кошельки с мультиподписью, то раскрытие одного закрытого ключа означает раскрытие всех остальных закрытых ключей по тому же BIP32 пути (а возможно, и по другим путям тоже). То есть если кошелек с мультиподписью получил биткойны на сотню разных адресов, то повторное использование одного-единственного nonce скомпрометирует все эти адреса.

Single-sig кошельки или те, что используют скриптовые multisig, могут избегать повторного использования nonce с помощью простого приема — сделав nonce зависимым от подписываемого сообщения. При любом изменении сообщения меняется nonce, и таким образом исключается его повторное использование.

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

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

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

Но даже если кошелек действительно генерирует высококачественные случайные nonce-значения, он должен гарантировать, что каждый nonce не используется больше одного раза. И это может быть нетривиальной задачей. Представьте себе MuSig2-совместимый холодный кошелек или (аппаратное) устройство электронной подписи, которые при первом запуске создают большое количество nonce. Затем этому кошельку или устройству необходимо будет обеспечить, чтобы ни один из этих nonce никогда не использовался более чем с одной частичной подписью. Звучит просто — увеличивайте счетчик при каждом использовании nonce, — но это может быть реальной проблемой, когда начинаешь прорабатывать все варианты случайного выхода из строя программы или устройства, не говоря уже о внешнем и, возможно, вредоносном вмешательстве.

Возможно, самый простой способ для кошелька снизить риск повторного использования nonce — это хранить их как можно меньше времени. Долговременное хранение nonce не только создает множество возможностей для того, чтобы что-то пошло не так, но и требует их записи на постоянный носитель, который может быть скопирован и восстановлен или иным образом переведен в неожиданное состояние. Другой возможный способ использования MuSig2 — это создавать nonce только по запросу, например, при получении PSBT. Nonce могут храниться в энергозависимой памяти то короткое время, в течение которого они необходимы, и автоматически уничтожаться (исключая повторное использование) в нескольких вариантах непредвиденных событий, таких как программный сбой или отключение питания.

Тем не менее криптографы, работающие над этой проблемой, похоже, очень обеспокоены отсутствием надежного способа предотвратить повторное использование nonce в исходном протоколе MuSig (MuSig1) и MuSig2. MuSig-DN (Deterministic Nonce) предлагает решение, но сложное и медленное (в альфа реализации на 2.9 GHz Intel i7 на создание доказательства nonce уходит почти секунда; неизвестно, сколько времени может занять эта операция на 16 MHz устройстве электронной подписи с гораздо менее продвинутым процессором).

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

Адаптеры подписи (signature adaptors)

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

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

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

Магия адаптеров

Signature adaptors (адаптеры подписи), часто называемые также adaptor signatures (адаптерными подписями), решают эти и многие другие проблемы, актуальные сегодня для систем, построенных на основе Биткойна. Хотя их можно использовать с ECDSA, текущей схемой подписи Биткойна, гораздо проще использовать адаптеры — приватно и без затрат — в сочетании с BIP340 реализацией схем Шнорра для taproot. Давайте посмотрим, как изменится приведенный выше пример при использовании адаптеров.

Как и прежде, жертвователь готовит транзакцию на 1000 BTC. Он подписывает транзакцию почти обычным способом, с той лишь разницей, что, по сути, генерирует свой nonce в двух частях: настоящий случайный nonce, который он всегда будет хранить в секрете, и свое любимое крупное число, которое изначально будет держаться в секрете, но которое можно безопасно открыть другим людям. Жертвователь генерирует валидную подпись, используя оба этих значения, — складывая их вместе, как если бы они были одним nonce.

Подписи BIP340 используют nonce в двух формах: в числовом представлении (называемом скаляром), которое обычно известно только автору подписи, и как точку на эллиптической кривой (ЭК), которая публикуется, чтобы обеспечить возможность проверки.

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

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

Как и все остальные, кто получил адаптер подписи жертвователя, Элис и Боб теперь имеют копию точки на ЭК для скрытого числа. Как и все остальные, они не знают настоящего скаляра. Но, как мы помним, всё, что сделал жертвователь для того, чтобы превратить свою валидную подпись в недействительную, — это вычел скрытое число из коммитмента своей подписи, сохранив, однако, привязку подписи к точке на ЭК для скрытого числа. Элис может с такой же легкостью создать невалидную подпись без привязки к скаляру, которого она не знает, но с указанием точки на ЭК, которая ей известна. Она делает это через создание собственной пары nonce-значений, используя при создании своей (недействительной) подписи закрытую форму nonce, но с привязкой к агрегированному значению открытой формы своего nonce и точки на ЭК из адаптера подписи жертвователя. Это создает адаптер подписи для транзакции, которая платит Бобу. Если Боб узнает скаляр, он сможет конвертировать этот адаптер в валидную подпись и отправить транзакцию, выиграв ставку.

Но как Боб узнает выигрышное число? Придется ли ему ждать, пока тот, кто его угадает, выпустит пресс-релиз? Нет. Напомню еще раз, что адаптер подписи, опубликованный жертвователем, представляет собой его действительную подпись минус скаляр. Когда скрытое число найдено и кто-то отправляет транзакцию на 1000 BTC, он должен опубликовать исходную (валидную) подпись. Боб, увидев эту транзакцию, может взять этот (валидный) коммитмент подписи и вычесть из него (невалидный) коммитмент подписи исходного адаптера, чтобы получить скаляр. Затем он использует этот скаляр для преобразования адаптера Элис в валидную подпись.

Адаптеры мультиподписи

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

Например, когда Элис и Боб из примера выше делают ставку, они могут начать с депозита в скрипт, который можно потратить, только предоставив мультиподпись между ними. Затем Элис может создать свою частичную подпись в форме адаптера подписи; если Боб узнаёт скрытое число, он может преобразовать адаптер Элис в ее валидную частичную подпись, а затем добавить свою частичную подпись и создать полную подпись, расходующую средства.

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

PTLC (Point Time Locked Contracts)

Есть несколько способов использования адаптеров подписи в Биткойне, но одним из вариантов, способных принести немедленную пользу, будут PTLC (Point Time Locked Contract), которые могут заменить собой HTLC (Hash Time Locked Contract), используемые уже многие годы. Это принесет несколько преимуществ, но сопряжено также с некоторыми трудностями. Чтобы понять оба вида контрактов, начнем с упрощенного примера использования HTLC; пример ниже может быть применим к офчейн lightning-платежам, ончейн coinswap-платежам или гибридным ончейн/офчейн-системам, таким как Lightning Loop, — именно благодаря этой гибкости HTLC нашли настолько широкое применение.

Элис хочет заплатить Кэрол, направив платеж через Боба, доверять которому ни Элис, ни Кэрол, не хотят. Кэрол создает случайный прообраз и хеширует его с помощью алгоритма SHA256. Кэрол передает хеш Элис, а прообраз держит в секрете. Элис инициирует в адрес Боба платеж, который тот может истребовать, представив подпись для своего открытого ключа плюс прообраз; или же через 10 блоков Элис может вернуть транзакцию себе, представив подпись для своего открытого ключа. Так выглядит описание этой политики на языке Minsc:

(pk($bob) && sha256($preimage)) || (pk($alice) && older(10))

Теперь Боб может инициировать в адрес Кэрол платеж на ту же сумму (возможно, за вычетом комиссий) с практически идентичным скриптом, только с обновленными сторонами и меньшим временем до возврата.

(pk($carol) && sha256($preimage)) || (pk($bob) && older(5))

Теперь Кэрол в течение пяти блоков может истребовать платеж от Боба в свой адрес, представив прообраз; это раскрывает прообраз Бобу и позволяет ему истребовать платеж в свой адрес от Элис, также в течение пяти блоков.

Проблемы приватности при использовании HTLC

Если скрипты из примера выше опубликованы ончейн, повторное использование того же хеша и прообраза сразу дает понять, что A платит C через B. Несколько менее очевидно, что это является проблемой также для протоколов офчейн-маршрутизации, таких как Lightning Network. Если представить себе более длинный путь маршрутизации, где один человек контролирует несколько отрезков этого пути, он сможет увидеть повторное использование того же хеша и прообраза, и исходя из этого определить, что некоторые ноды являются узлами маршрутизации, что увеличивает вероятность того, что остальные ноды являются либо отправителями, либо получателями. Это одна из составляющих проблемы возможности связывания — возможно, самой серьезной проблемы Lightning Network в области приватности на сегодняшний день.

Готовясь к активации Taproot

Хотя multipath (разветвленные) платежи частично смягчают другие аспекты проблемы связываемости в LN — как, например, возможность связывания по сумме платежа, — это может усугубить проблему связываемости по хешу, предоставляя маршрутизирующим нодам больше возможностей для отслеживания корреляции хешей.

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

Решение PTLC

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

(pk($bob) && pk($alice_adaptor)) || (pk($alice) && older(10))
(pk($carol) && pk($bob_adaptor)) || (pk($bob) && older(5))

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

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

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

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

На двух отрезках этого пути, Элис→Боб и Боб→Кэрол, использовались разные точки на ЭК и скаляры, исключая возможность связывания (ассоциирования) платежей между собой. Это можно распространить на более длинный путь — как тот, что мы рассматривали в примере с HTLC, — и посмотреть, как это улучшает приватность:

Готовясь к активации Taproot

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

pk($bob_with_alice_adaptor) || (pk($alice) && older(10))
pk($carol_with_bob_adaptor) || (pk($bob)   && older(5) )

С taproot левую ветвь можно использовать как keypath, путь до ключа, а правую — как tapleaf, лист taproot дерева. При успешной маршрутизации платежа, Боб и Кэрол смогут завершить расчет по своим частям ончейн без дальнейшего взаимодействия со своими контрагентами, что сделает этот маршрутизированный платеж неотличимым от single-sig платежей, обычных платежей с мультиподписью и совместно разрешаемых контрактов. Это также минимизирует использование пространства блоков. При активации одного из условий возврата метод все еще остается достаточно эффективным и довольно конфиденциальным — pk(x) && older(n) неотличимо от degrading multisig (сокращение множества мультиподписи), enforced hodling (вынужденный ходлинг) и множества других возможных скриптов.

Lightning Network с taproot

Эта часть написана ZmnSCPxj, разработчиком протокола Lightning Network. В ней автор рассматривает две функции приватности, обеспечиваемые taproot для Lightning Network:

  • PTLC в LN,
  • P2TR каналы.

PTLC в Lightning Network

PTLC позволяют реализовать множество функций, самой важной из которых для LN, как уже говорилось в предыдущей части, является декорреляция платежей без необходимости рандомизировать маршруты.[3] Каждому узлу на пути простого (single-path) или разветвленного (multipath) маршрута может быть присвоен скаляр, который используется для подстройки каждого пересылаемого PTLC, обеспечивая декорреляцию платежей, при которой в отдельных пересылках больше не происходит утечки уникального идентификатора для каждого LN платежа.

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

  • Повышение неопределенности в результатах анализа. Надежность доступных для наблюдателя вероятностей теперь ниже, а значит, полученная таким образом информация имеет намного меньшую ценность.
  • Гораздо большую декорреляцию в multipath платежах. Пути не будут иметь сильной корреляции друг с другом по таймлоку и сумме, и в случае успеха LN должно быть достаточно платежей, чтобы корреляция по времени также не давала надежного результата.
  • Никакого увеличения затрат по сравнению с HTLC (возможно, даже снижение затрат благодаря эффективности мультиподписи).

В принципе, pre-taproot канал может быть обновлен до поддержки PTLC без необходимости закрывать канал и открывать его заново. Существующие каналы могут разместить PTLC путем создания офчейн-транзакции, расходующей существующий не-taproot выход на taproot-выход, содержащий PTLC. Это означает, что добавление поддержки для PTLC через LN не требует никаких затрат от операторов узлов и обновления оборудования от их пиров.

Однако для фактического использования PTLC каждый форвардный узел на маршруте от отправителя до получателя должен поддерживать PTLC. Это означает, что реальная поддержка PTLC может не наступить до тех пор, пока не будет обновлено достаточное количество узлов. Им не обязательно использовать один и тот же протокол (PTLC протоколов может быть несколько), но все они должны поддерживать какой-либо из PTLC протоколов. Необходимость поддерживать несколько PTLC протоколов дополнительно усложнит поддержку и разработку LN, так что я надеюсь, что их будет не слишком много (в идеале, конечно, один).

P2TR каналы

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

К сожалению, каждый LN канал требует сотрудничества между двумя подписывающими сторонами, и до активации taproot каждый 2-из-2 скрипт в Биткойне открыто кодируется. LN — самый активный пользователь мультиподписи 2-из-2, поэтому любой блокчейн-эксплорер может показать, что это транзакция закрытия LN канала. Затем средства можно отследить, и если они направляются на другой P2WSH выход, то, скорее всего, это будет еще один неопубликованный канал. Таким образом, даже неопубликованные каналы можно идентифицировать ончейн после их закрытия, с некоторым уровнем ложных срабатываний, конечно.

Taproot, используя схемы Шнорра, позволяет n-of-n подписям выглядеть в точности как 1-of-1. После некоторой обработки даже k-of-n (пороговые) подписи будут выглядеть так же, как 1-of-1 (и n-of-n). Затем мы можем предложить опцию, в которой LN канал обеспечивается P2TR UTXO — P2TR-канал, — что повышает уровень ончейн приватности для неопубликованных («приватных») каналов.[4]

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

Кроме того, taproot расходования по keypath «весят» на 40% меньше (38,5 vБайт), чем P2WSH платежи, используемые в LN. К сожалению, обновить существующий pre-taproot канал до P2TR нельзя. В существующих каналах используются P2WSH со схемой 2-из-2, и для переключения на P2TR такие каналы придется закрыть.

В теории outpoint, отправная точка канала, задаваемая транзакцией финансирования, касается только двух узлов, использующих этот канал. Другие узлы сети не беспокоятся о том, что обеспечивает канал между любыми двумя узлами. Однако информация об опубликованных каналах распространяется по gossip-сети Lightning. Когда узел получает данные о таком опубликованном канале, он сверяется с полным биткойн-узлом по своему выбору, проверяя, что финансирующий канал outpoint существует и, что более важно, имеет корректный адрес. Проверка адреса затрудняет спам механизма распространения информации о канале; нужно внести реальные средства в контракт, записываемый в блокчейн, чтобы информация о канале распространилась по gossip-сети LN. Таким образом, на практике даже P2TR каналы требуют некоторой удаленной совместимости; в противном случае отправители будут игнорировать эти каналы для маршрутизации, поскольку не смогут подтвердить их существование.

Временные рамки

Я думаю, что лучший способ задать ориентировочные временные рамки для реализации функций в распределенном FOSS (Free and Open-Source Software) проекте — это взять за основу предыдущие функции и то, сколько времени заняла их реализация.[5]

Последняя важная функция, на мой взгляд, аналогичная по масштабу PTLC в LN, — это двустороннее (дуальное) финансирование канала. Lisa Neigut создала первоначальное предложение для протокола двустороннего финансирования в BOLT #524, но первый канал с двусторонним финансированием в основной сети был открыт почти на два с половиной года позже. Двустороннее финансирование требует совместимости только с вашими прямыми пирами. В то время как PTLC через LN требует совместимости со всеми маршрутизирующими узлами на выбранных маршрутах, включая получателя, так что я считаю оправданным умножить время, необходимое на реализацию этой функции, на 1,5 из-за дополнительной сложности. В результате мы получаем ориентировочные 3 года и 9 месяцев от момента предложения конкретного PTLC протокола.

Что касается P2TR каналов, то нужно отметить, что, хотя здесь речь идет о взаимодействии «только» между двумя прямыми пирами, они также дают меньше преимуществ. Так что я ожидаю, что эта задача будет иметь меньший приоритет. Если предположить, что большинство разработчиков отдадут приоритет PTLC через LN, то я ожидаю, что P2TR каналы начнут работать к тому времени, когда будут доступен базовый SIGHASH_ANYPREVOUT или другие способы реализовать предложение Decker-Russell-Osuntokun (Eltoo).

Vault с taproot

Автор этой части — Antoine Poinsot, разработчик Revault.

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

В отличие от группирования (batching) платежей, когда в одной ончейн-транзакции выполняется несколько платежей, в vault несколько транзакций используются для выполнения одного платежа. Первая транзакция, unvault, платит либо:

  1. набору открытых ключей после относительной блокировки по времени (таймлока) или
  2. одному открытому ключу без каких-либо таймлоков.

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

Таким образом, концепция vault идет несколько вразрез с идеей taproot о том, что большинство контрактов предусматривают «счастливый путь», в котором все участники сотрудничают через подпись (а путь оспаривания обычно содержит временные блокировки). Скорее наоборот. Для транзакции расходования необходимо использовать taproot-скрипт, поскольку он ограничен относительным таймлоком [6], в то время как транзакция отмены теоретически может выполняться через расходование по ключу.

Поскольку многосторонние vaults на практике требуют уже большой интерактивности, теоретически они могли бы выиграть от интерактивных схем многосторонней и пороговой подписи, ставших возможными благодаря BIP340, таких как MuSig2. Однако эти схемы сопряжены с новыми вызовами в области безопасности. Поскольку vault протоколы предназначены в первую очередь для использования с холодными хранилищами, выбор дизайна здесь носит более консервативный характер, и вероятно, что vault последними начнут использовать эти новые технологии.

Переход на taproot также обеспечит для vault некоторое повышение приватности и эффективности за счет использования ветвей Меркла и более коротких BIP340 подписей (особенно для многосторонних транзакций). Например, unvault скрипт выхода в многостороннем сетапе с 6 «холодными» и 3 «активными» ключами (с порогом 2) может быть представлен как taproot глубиной 2 и с листьями:

  • <X> CSV DROP <active key 1> CHECKSIG <active key 2> CHECKSIGADD 2 EQUAL
  • <X> CSV DROP <active key 2> CHECKSIG <active key 3> CHECKSIGADD 2 EQUAL
  • <X> CSV DROP <active key 3> CHECKSIG <active key 1> CHECKSIGADD 2 EQUAL
  • <cold key 1> CHECKSIG <cold key 2> CHECKSIGADD <cold key 3> CHECKSIGADD <cold key 4> CHECKSIGADD <cold key 5> CHECKSIGADD <cold key 6> CHECKSIGADD 6 EQUAL

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

IF
  6 <cold key 1> <cold key 2> <cold key 3> <cold key 4> <cold key 5> <cold key 6> 6 CHECKMULTISIG
ELSE
  <X> CSV DROP
  2 <active key 1> <active key 2> <active key 3> 3 CHECKMULTISIG
ENDIF

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

Наконец, vault протоколы, как и большинство протоколов на основе предварительно подписанных транзакций, в значительной степени выиграют от от дальнейших предлагаемых обновлений на основе taproot, таких как SIGHASH_ANYPREVOUT из BIP118. Хоть и требуя дополнительных мер предосторожности и донастройки протокола, ANYPREVOUT и ANYPREVOUTANYSCRIPT позволят реализовать повторно привязываемые (rebindable) подписи отмены, что может в значительной мере уменьшить требуемый уровень интерактивности и позволить хранение с подписью 0(1). Это особенно интересно для аварийной подписи в протоколе Revault, так как в значительной степени снизит поверхность DoS атак. Имея в выходе подпись ANYPREVOUTANYSCRIPT, вы фактически создаете ковенант, ограничивая то, как транзакция расходования этих монет может создавать свои выходы. Еще более настраиваемые хеши будущих подписей позволят реализовывать еще более гибкие ограничения.

Схемы безопасности и восстановления доступа к средствам

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

  • Простая 2-из-3: как уже упоминалось в предыдущем разделе, комбинацию из расходов по мультиподписи и по скрипту легко можно использовать для создания политики расходования 2-из-3, которая обычно обладает такой же ончейн эффективностью, что и single-sig расходование, и обеспечивает намного большую приватность, чем текущие P2SH и P2WSH мультиподписи. В нестандартных случаях это все еще довольно эффективно и конфиденциально. Поэтому taproot отлично подходит для повышения уровня безопасности кошелька с одной подписью до политики с многосторонней подписью.Мы ожидаем, что будущие методы для пороговых подписей еще больше улучшат работу с 2-of-3 и другими k-of-n случаями.
  • Сокращение множества (degrading) мультиподписи: одно из упражнений в Optech Taproot Workshop позволяет вам поэкспериментировать с созданием taproot-скрипта, который можно потратить в любое время с тремя ключами или после трех дней с двумя из исходных ключей, или после десяти дней со всего одним из исходных ключей. (В упражнении используются также ключи восстановления, но это мы рассмотрим отдельно в следующем пункте.) Возможности настройки параметров времени и ключей обеспечивает гибкую и мощную модель для аварийного восстановления доступа к средствам.Для примера, представьте, что обычно вы можете расходовать средства, используя комбинацию из ноутбука, мобильного телефона и отдельного устройства электронной подписи. На случай если одно из этих устройств станет недоступно, через месяц открывается возможность распоряжаться этими средствами с помощью двух устройств из первоначального списка. Если два устройства становятся недоступны, то через шесть месяцев средствами можно будет распоряжаться с помощью только одного из этих устройств.В нормальном случае, при использовании всех трех устройств, ваш ончейн-скрипт максимально эффективен и приватен. В остальных случаях он несколько менее эффективен, но все еще может быть достаточно приватным (ваш скрипт и глубина его дерева будут похожи на параметры, используемые во многих других контрактах).
  • Социальное восстановление резервных копий и схем безопасности: пример выше отлично защищает, если злоумышленник украдет одно из ваших устройств, но что, если будут украдены два устройства? Кроме того, если вы часто пользуетесь кошельком, готовы ли и хотите ли вы ждать месяц после потери устройства, прежде чем сможете снова тратить с него деньги?Taproot позволяет легко, дешево и приватно добавлять в ваши схемы восстановления доступа социальный элемент. В дополнение к скриптам из предыдущего примера, вы можете также разрешить немедленное расходование ваших биткойнов с двумя из ваших устройств плюс подписями двух ваших друзей или членов семьи. Или немедленное расходование только с одним из ваших ключей и подписями пяти людей, которым вы доверяете. (Аналогичной не-«социальной» версией этого сетапа было бы просто использование дополнительных устройств или seed-значений, сохраненных в различных сравнительно безопасных местах.)
  • Сочетание временных и социальных пороговых значений для наследования: комбинируя описанные выше методы, вы можете позволить кому-то одному или группе людей восстановить средства в случае вашей внезапной смерти или утраты трудоспособности. Например, вы можете позволить своему адвокату или любым трем из пяти наиболее доверенных родственников потратить свои монеты, если они не перемещались в течение шести месяцев. Если обычно вы в любом случае оперируете своими биткойнами в течение шестимесячного периода, то такой сетап наследования не требует дополнительных ончейн затрат пока вы живы, и полностью скрыт от сторонних наблюдателей. Вы даже можете хранить совершаемые транзакции в тайне от своего адвоката и семьи, если у вас предусмотрен надежный способ передачи им расширенного открытого ключа (xpub) от кошелька после вашей смерти.Пожалуйста, обратите внимание, что предоставление вашим наследникам возможности расходовать ваши биткойны само по себе не означает, что они смогут это делать на законных основаниях. Мы рекомендуем всем, кто планирует передать свои биткойны по наследству, прочесть книгу Памелы Морган «Cryptoasset Inheritance Planning» (физическая книга и электронная версия с DRM или электронная книга без DRM) и использовать эту информацию при обсуждении деталей с местным экспертом по планированию наследования.
  • Определение компрометации устройства: идея, предложенная еще до изобретения taproot, состоит в том, чтобы поместить ключ, контролирующий какое-то количество биткойнов, на все устройства, в которых вы заинтересованы, в качестве способа определения того, что устройство было скомпрометировано. Если сумма достаточно велика, то злоумышленник, вероятно, выведет ее немедленно, а не будет ждать, чтобы использовать свой незаконный доступ в более долгосрочной атаке, способной нанести вам больший общий ущерб.Проблема с этим подходом состоит в том, что вы хотите сделать предлагаемое количество биткойнов достаточно большим, чтобы соблазнить злоумышленника немедленным выводом, но при этом размещать достаточную сумму на каждое из устройств еще более обременительно — предпочтительнее было бы выделить нужную сумму только один раз. Однако если положить на каждое из устройств один и тот же ключ, то расход общих биткойнов не покажет, какое именно из устройств оказалось скомпрометировано. Taproot позволяет легко установить на каждое устройство отдельный ключ с другим путем к скрипту (scriptpath). Любой из этих ключей сможет потратить средства с одного общего адреса, но в силу уникальности ключа это однозначно покажет, какое из устройств было скомпрометировано.

Тестирование в signet

Хотя до блока 709 632 безопасно использовать taproot в основной сети нельзя, его можно протестировать и до активации в тестовой сети testnet либо signet. В сравнении с созданием локальной тестовой сети в тестовом режиме Bitcoin Core, как это делается в методичке Bitcoin Optech, использование testnet или signet упрощает тестирование взаимодействия вашего сервиса с кошельками других людей.

В этом разделе мы получим и потратим taproot транзакцию в signet с помощью встроенного кошелька Bitcoin Core. Вам, вероятно, будет нужно адаптировать эти инструкции для тестирования приема и расходования между вашим кошельком и Bitcoin Core.

Хотя технически возможно получать и отправлять taproot транзакции с помощью встроенного кошелька Bitcoin Core 22.0, мы рекомендуем вместо этого использовать сборку Bitcoin Core из пулл-реквеста #22364, делающую taproot дефолтной опцией для дескрипторных кошельков. После сборки запустите signet:

$ bitcoind -signet -daemon

При первом использовании signet вам понадобится синхронизировать ее блокчейн. На сегодня он включает около 200 Мб данных и может полностью синхронизироваться всего за минуту. Вы можете отслеживать прогресс синхронизации, используя RPC-вызов getblockchaininfo. После синхронизации создайте дескрипторный кошелек:

$ bitcoin-cli -signet -named createwallet wallet_name=p4tr descriptors=true load_on_startup=true
{
  "name": "p4tr",
  "warning": "Wallet is an experimental descriptor wallet"
}

Теперь вы можете создать bech32m адрес:

$ bitcoin-cli -named -signet getnewaddress address_type=bech32m
tb1p6h5fuzmnvpdthf5shf0qqjzwy7wsqc5rhmgq2ks9xrak4ry6mtrscsqvzp

С этим адресом вы можете запросить средства у крана signet. Затем вам нужно будет дождаться подтверждения, занимающего примерно столько же времени, сколько и в основной сети (обычно до 30 минут, но бывает и дольше). Если вы взглянете на транзакцию, то увидите созданный вами P2TR скрипт.

$ bitcoin-cli -signet getrawtransaction 688f8c792a7b3d9cb46b95bfa5b10fe458617b758fe4100c5a1b9536bedae4cd true | jq .vout[0]
{
  "value": 0.001,
  "n": 0,
  "scriptPubKey": {
    "asm": "1 d5e89e0b73605abba690ba5e00484e279d006283bed0055a0530fb6a8c9adac7",
    "hex": "5120d5e89e0b73605abba690ba5e00484e279d006283bed0055a0530fb6a8c9adac7",
    "address": "tb1p6h5fuzmnvpdthf5shf0qqjzwy7wsqc5rhmgq2ks9xrak4ry6mtrscsqvzp",
    "type": "witness_v1_taproot"
  }
}

Затем вы можете создать второй bech32m адрес и отправить на него средства для проверки расходования.

$ bitcoin-cli -named -signet getnewaddress address_type=bech32m
tb1p53qvqxja52ge4a7dlcng6qsqggdd85fydxs4f5s3s4ndd2yrn6ns0r6uhx
$ bitcoin-cli -named -signet sendtoaddress address=tb1p53qvqxja52ge4a7dlcng6qsqggdd85fydxs4f5s3s4ndd2yrn6ns0r6uhx amount=0.00099
24083fdac05edc9dbe0bb836272601c8893e705a2b046f97193550a30d880a0c

В этом расходе мы можем посмотреть на один из входов и увидеть, что его witness-поле не содержит ничего, кроме одной 64-байтовой подписи. Это «весит» меньше vБайт, чем witness, который бы потребовался для расхода P2WPKH или любого другого старого типа скрипта.

$ bitcoin-cli -signet getrawtransaction 24083fdac05edc9dbe0bb836272601c8893e705a2b046f97193550a30d880a0c true | jq .vin[0]
{
  "txid": "bd6dbd2271a95bce8a806288a751a33fc4cf2c336e52a5b98a5ded432229b6f8",
  "vout": 0,
  "scriptSig": {
    "asm": "",
    "hex": ""
  },
  "txinwitness": [
    "2a926abbc29fba46e0ba9bca45e1e747486dec748df1e07ee8d887e2532eb48e0b0bff511005eeccfe770c0c1bf880d0d06cb42861212832c5f01f7e6c40c3ce"
  ],
  "sequence": 4294967294
}

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

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

Со времени активации segwit более четырех лет назад не существовало общепринятого способа создавать подписанные текстовые сообщения для bech32 или bech32m адресов. Возможно, это значит, что широкое распространение поддержки подписи сообщений, по-видимому, не очень важна для пользователей или разработчиков, — иначе этому было бы уделено больше работы. Однако есть впечатление некоторого регресса биткойн-кошельков с тех времен, когда все использовали классические стандартные адреса и могли легко обмениваться подписанными сообщениями.

Решение generic signmessage потерпело неудачу, не будучи реализованным даже в Bitcoin Core, несмотря на периодические обновления документации его протокола, BIP322. Несмотря на это, лучшей альтернативы мы не знаем, и потому BIP322 по-прежнему следует рассматривать как предпочтительный выбор для любого разработчика, который хочет добавить поддержку универсальных подписанных сообщений в свой P2TR кошелек.

Будучи реализованным, generic signmessage позволит подписывать сообщения для P2TR выходов, будь то с односторонней, многосторонней подписью или с использованием любого из tapscript-скриптов. Это также обеспечит обратную совместимость со всеми legacy и bech32 адресами, а также совместимость со всеми типами изменений, запланированных на ближайшее будущее (о некоторых из которых мы расскажем ниже). Приложения с доступом к полному UTXO-сету (например, через полную ноду) могут также использовать BIP322 для создания и проверки доказательств резервов (reserve proofs), предоставляя доказательства того, что подписавший по состоянию на определенный момент времени контролирует определенное количество биткойнов.

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

Проверка универсальных подписанных сообщений для многих кошельков может быть существенно сложнее. Чтобы получить возможность полноценно проверить любое BIP322 сообщение, необходимо реализовать практически все правила консенсуса Биткойна. Большинство кошельков этого не делают, поэтому BIP322 позволяет им возвращать «неокончательное», «неоднозначное» (inconclusive) состояние, когда они не могут полностью проверить скрипт. На практике, и особенно с учетом поощрения в taproot расходования по keypath, это может быть редкостью. Любой кошелек, в котором реализовано всего несколько наиболее популярных типов скриптов, сможет проверять подписанные сообщения для 99% всех UTXO.

Поддержка generic signmessage, универсальных подписанных сообщений, стала бы полезным дополнением к Биткойну. Хоть мы и не можем игнорировать недостаток внимания к этой теме в последние несколько лет, но хочется отметить, что для разработчиков кошельков поддержка generic signmessage даже в экспериментальном режиме — это простой способ вернуть пользователям функцию, которой они были лишены уже несколько лет. Если вы разработчик, работающий над реализацией BIP322 или связанных с ним доказательств резервов (reserve proof), или, может быть, управляющий сервисом, который сочтет такие функции полезными, не стесняйтесь написать на info@bitcoinops.org для координации усилий.

Связывание выходов

После активации taproot пользователи начнут получать платежи на P2TR выходы. Позже они будут расходовать эти выходы. В некоторых случаях они будут производить платежи на выходы, отличные от P2TR, но сдачу все равно будут получать на новый P2TR выход.

Готовясь к активации Taproot

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

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

  • Другие метаданные: транзакции могут содержать и другие метаданные, показывающие, какие выходы предназначены для получения сдачи, а какие являются платежными. Одним из наиболее тревожных факторов на сегодня является процент повторного использования адресов, что значительно снижает уровень приватности как для отправителя, так и для получателя таких транзакций. И поскольку эта проблема сохраняется достаточно давно, кажется неразумным не поддержать реализацию кошельками и сервисами значительных улучшений приватности и внедрения лучших доступных практик.
  • Сопоставление выходов скриптов: встроенный кошелек Bitcoin Core по умолчанию использует segwit-выход для сдачи, если какой-либо из платежных выходов также является segwit. В противном случае он использует тип адреса для сдачи по умолчанию. Например, при оплате на P2PKH выход может использоваться P2PKH выход для сдачи; для P2WPKH выхода всегда используется P2WPKH выход для сдачи. После активации taproot Bitcoin Core начнет оппортунистически использовать P2TR выходы для сдачи, если один из расходных выходов этой транзакции будет P2TR. Это может свести к минимуму любое увеличение возможности идентификации выходов для сдачи в переходный период.
  • Запрос обновлений: с P2TR у нас, вне зависимости от требований к безопасности, впервые в истории Биткойна появилась возможность всем использовать один тип скриптов выходов, а также часто использовать неразличимые между собой входы транзакций, что значительно повышает уровень приватности. Если вы хотите скорее увидеть значительное повышение приватности Биткойна, то можете попросить пользователей и сервисам, в адрес которых вы делаете выплаты, поддержать taproot (и перестать повторно использовать адреса, если применимо). Если и вы, и получатели ваших платежей обновитесь, то определить выходы для сдачи будет сложнее, плюс мы получим все остальные замечательные преимущества taproot в области конфиденциальности транзакций.

Всегда ли нужна опция сотрудничества?

Оригинальное предложение taproot авторства Грегори Максвелла включало интересный принцип построения контракта:

«Почти всегда бывает так, что интересные скрипты имеют логическую ветвь верхнего уровня, которая позволяет выполнение контракта только с подписями всех сторон. Другие ветви будут использоваться только в тех случаях, когда какой-либо участник отказывается от взаимодействия. Строго говоря, я считаю, что любой контракт с фиксированным и конечным набором участников может и должен быть представлен как ИЛИ между N-of-N и любым более сложным контрактом, который вы можете захотеть представить».

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

  • Пользовательский самоконтроль средствами консенсуса сети: некоторые люди использовали временные блокировки, таймлоки, чтобы исключить трату собственных биткойнов в течение определенного времени. Требование временной блокировки, по-видимому, предполагает, что требуется нечто большее, чем одна подпись, однако было высказано несколько критических замечаний:
    • Кто-то всерьез отчаявшись потратить свои заблокированные биткойны, может взять кредит — возможно, под залог какого-либо другого актива, — что подрывает полезность такого контракта с самим собой.
    • В дополнение к таймлоку по пути скрипта (scriptpath), пользователь может разрешить расходование по keypath между своим ключом и ключом третьей стороны, которая предоставляет подпись только по истечении временной блокировки. Это не только более эффективно, но и позволяет реализовать более гибкую политику, такую как предоставление пользователю возможности продать любые полученные им форк-койны или взаимодействовать с третьей стороной, которая позволит ему потратить монеты до срока в случае серьезных изменений в жизни или повышения цен.
  • Vaults: как писал Antoine Poinsot выше, vaults также широко используют временную блокировку для защиты средств, что, по-видимому, «идет несколько вразрез с идеей taproot о том, что большинство контрактов предусматривают «счастливый путь», в котором все участники сотрудничают через подпись». Другие утверждали, что не существует сценария, в котором пользователь vault не хотел бы иметь возможности избежать условий такого контракта через расходование по keypath, и что, поскольку добавление соответствующего параметра в контракт ничего не стоит, было бы строго лучше включить такую опцию.

Аргумент против того, чтобы всегда предоставлять опцию расхода по keypath, по-видимому, заключается в том, что бывают случаи, в которых даже все совместно действующие подписанты не доверяют в полной мере себе. Однако они готовы доверять другим людям — операторам экономических полных узлов, обеспечивающих соблюдение правил консенсуса Биткойна, — в том, чтобы те обеспечили соблюдение ограничений на расходование вместо самих подписантов.

Контраргумент состоит в том, что, по крайней мере чисто теоретически, вы можете обеспечить тот же уровень безопасности, создав расход по keypath между обычными подписантами и всеми этими операторами экономических полных нод. С практической точки зрения, вероятно, существует некое подмножество или альтернативный набор этих операторов узлов, которые могут быть добавлены в множество мультиподписи для вашего расхода по ключу и которые будут применять желаемую политику, если они доступны (если нет, вы ничего не теряете, так как по-прежнему можете использовать расход по scriptpath).

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

Будущие изменения консенсуса

Пока taproot приближается к активации на блоке 709 632, мы можем уже начинать с нетерпением ожидать некоторых изменений консенсуса, о желании реализовать которые «поверх» taproot разработчики уже упоминали ранее.

  • Агрегация подписей для разных входов: схемы Шнорра позволяют владельцам нескольких пар открытых и закрытых ключей создавать одну подпись, подтверждающую, что владельцы всех этих ключей действовали сообща для создания этой подписи. С будущим изменением консенсуса это может позволить транзакции содержать единую подпись, подтверждающую, что владельцы всех UTXO, расходуемых в этой транзакции, санкционировали соответствующие траты. Это позволит сэкономить около 16 vБайт на каждый keypath после первого входа, обеспечивая значительную экономию для консолидированных и coinjoin-транзакций. Это может сделать расходование через coinjoin дешевле, чем обычные одиночные транзакции, создавая мягкий стимул к применению более приватных практик.
  • SIGHASH_ANYPREVOUT: каждая обычная биткойн-транзакция включает один или несколько входов, и каждый из этих входов ссылается на выход предыдущей транзакции через ее txid. Такие ссылки сообщают полным верифицирующим узлам — как Bitcoin Core, — сколько денег может быть потрачено в этой транзакции и какие условия должны быть выполнены, чтобы подтвердить, что траты были авторизованы. Все способы генерации подписей для биткойн-транзакций, как с taproot, так и без него, либо привязываются к txid предыдущих выходов, либо не привязываются к предыдущим выходам вовсе.Это является проблемой для многопользовательских протоколов, которые не хотят использовать точную заранее подготовленную серию транзакций. Если какой-либо пользователь может пропустить определенную транзакцию или изменить какие-то детали любой транзакции, кроме ее witness-данных, это изменит txid любой последующей транзакции. Изменение txid делает недействительными все подписи, созданные ранее для последующих транзакций. Это вынуждает офчейн-протоколы внедрять механизмы (такие как LN-penalty), наказывающие любого пользователя, отправляющего более старую транзакцию. SIGHASH_ANYPREVOUT может устранить эту проблему, позволив подписи пропускать привязку к txid предыдущего выхода. В зависимости от других используемых флагов, она по-прежнему будет ссылаться на другие данные о предыдущем выходе и транзакции (такие как сумма и скрипт), но то, какой txid использовался для предыдущей транзакции, больше не будет иметь значения. Это позволит реализовать и eltoo уровень для Lightning Network, и некоторые улучшения в протоколах vaults и других контрактов.
  • Делегирование и обобщение: после создания скрипта (taproot или какого-то иного) у вас почти нет возможностей для делегирования дополнительным людям права потратить средства из этого скрипта, кроме как передать им свой закрытый ключ, что может быть очень опасно при использовании BIP32 кошельков. Кроме того, taproot можно сделать более доступным для пользователей, которые хотят использовать расходы по keypath плюс очень небольшое количество условий на основе скриптов. Было предложено несколько методов улучшения и развития taproot:
    • Graftroot: предложенный вскоре после публикации идеи taproot, graftroot предусматривает предоставление дополнительной функции любому, кто может совершать taproot расходование по keypath. Вместо того чтобы тратить средства напрямую, отправители по keypath могли бы вместо этого подписать скрипт, описывающий новые условия расходования средств, делегируя право их расхода любому, кто сможет выполнить требования скрипта. Подпись, скрипт и любые другие данные, необходимые для удовлетворения требований скрипта, будут предоставлены в расходной транзакции. Таким образом отправители, подписанты по keypath, могут делегировать неограниченное количество скриптов, не создавая никаких ончейн-данных до тех пор, пока не произойдет фактического расходования.
    • Generalized taproot (g’root): несколько месяцев спустя Энтони Таунс предложил способ использовать точки открытого ключа для выполнения нескольких различных условий расходования без необходимости использовать MAST-подобную конструкцию. Конструкция generalized taproot (g’root) «потенциально более эффективна для случаев, когда основное допущение taproot не выполняется». Это также «предлагает простой способ построить безопасную для софтфорка систему агрегирования перекрестных входов».
    • Entroot: более поздний синтез graftroot и g’root, упрощающий многие сценарии и делающий их более эффективными с точки зрения пропускной способности. Он может поддерживать делегирование подписи от любого, кто сможет удовлетворить требованиям любой из entroot ветвей, а не только тех, кто может создать расход по keypath верхнего уровня.
  • Новые и старые опкоды: софтфорк taproot включает поддержку tapscript, обеспечивающего улучшенный способ добавления новых опкодов в Биткойн, опкоды OP_SUCCESSx. Подобно OP_NOPx (без операции), добавленным на ранних этапах истории Биткойна, OP_SUCCESSx предназначены для замены опкодами, которые не всегда возвращают успех. Некоторые предлагаемые новые опкоды включают:
    • Восстановление старых опкодов: ряд опкодов для математических и строковых операций был отключен в 2010 году из опасений по поводу возможных уязвимостей. Многие разработчики хотели бы возвращения поддержки этих опкодов после проверки на безопасность и (в некоторых случаях), возможно, расширения их для работы с бо́льшими числами.
    • OP_CAT: один из ранее отключенных кодов операций, заслуживающий отдельного упоминания. Как с тех пор обнаружили исследователи, OP_CAT и сам по себе открывает возможности для самых разнообразных интересных действий в Биткойне, но может быть и объединен с другими новыми опкодами.
    • OP_TAPLEAF_UPDATE_VERIFY: предложенный Энтони Таунсом опкод OP_TLUV, как писалось в рассылке Bitcoin Optech, позволяет создавать ковенанты и особенно эффективен и полезен может быть при использовании с keypath и scriptpath возможностями taproot. Его можно использовать для реализации joinpools, vaults и других улучшений безопасности и приватности. Он также может хорошо сочетаться с OP_CHECKTEMPLATEVERIFY.

Все эти идеи на сегодня находятся только на стадии предложения. Успех ни одного из них не гарантирован. Сначала исследователи и разработчики должны довести каждое предложение до достаточно зрелого состояния, затем пользователи будут определять, стоит ли добавление каждой из этих функций усилий, связанных с изменением правил консенсуса Биткойна.

Что произойдет при активации?

Активация taproot должна произойти уже в воскресенье 14 ноября, на блоке 709 632. Мы знаем, что должно произойти и мы также знаем о нескольких вероятных сценариях сбоя.

Лучший и наиболее вероятный вариант — это что всё пройдёт хорошо. Обычным пользователям происходящее вообще не должно быть видно. Только те, кто тщательно следит за своими нодами или пытается создать taproot транзакции, вероятно, заметят изменения. В блоке 709 631 практически все полные узлы, о которых мы знаем, будут применять одни и те же правила консенсуса. На следующем же блоке узлы с клиентом Bitcoin Core 0.21.1, 22.0, или связанных версий начнут применять дополнительные taproot правила, не предусмотренные в более ранних версиях ПО.

Это несет в себе риск того, что более ранние и более поздние версии программных клиентов будут принимать в качестве валидных разные блоки. Так произошло при активации софтфорка BIP66 в 2015 году, что привело к разделению блокчейна в течение 6 блоков и нескольким более коротким разделениям. Для предотвращения повторения подобного сценария были приложены значительные инженерные усилия. С taproot что-то подобное может произойти, только если майнер намеренно добывает блок, недопустимый для taproot, либо если он отключил меры безопасности, жестко закодированные в Bitcoin Core или другом клиентском ПО узлов Биткойна.

В частности, чтобы создать разделение блокчейна, майнеру понадобится создать или принять транзакцию, расходующую биткойны с taproot (segwit v1) выхода, не следуя при этом правилам taproot. Если майнер это сделает, он потеряет по меньшей мере 6,25 BTC (более $400 тыс. по состоянию на четверг 11 ноября), если экономический консенсус операторов биткойн-нод отвергнет некорректные согласно taproot блоки.

До появления некорректного блока мы не можем сказать наверняка, как себя поведут эти операторы узлов — ноды могут функционировать совершенно приватно, — но косвенные показатели указывают на то, что более 50% операторов нод используют версии Bitcoin Core с поддержкой taproot. Этого, по-видимому, более чем достаточно, чтобы гарантировать, что любой недопустимый согласно taproot блок будет отклонен сетью.

Хоть и очень маловероятно, но теоретически кратковременное разделение блокчейна возможно. Это должно быть можно отследить в таких сервисах, как ForkMonitor.info или с помощью PRC-вызова getchaintips в Bitcoin Core. Если это произойдет, легкие клиенты могут получить ложные подтверждения. Хотя в теории число таких подтверждений может достигать и шести, как это было при разделении блокчейна в 2015 году, это означало бы, что майнеры потеряли на этом почти $2,5 млн (в сравнении с ~$50 тыс. в 2015). Мы можем надеяться, что с настолько весомым финансовым стимулом майнеры действительно будут применять правила taproot, о готовности к чему они сигнализировали за шесть месяцев до того.

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

Для пользователей и сервисов, которые совершенно убеждены, что экономический консенсус операторов полных узлов будет обеспечивать соблюдение правил taproot, еще более простым решением будет получать данные только о тех транзакциях, которые получили подтверждение в Bitcoin Core версии 0.21.1 и выше (либо совместимой альтернативной реализацией ноды).

Bitcoin Optech и BitNovosti ожидают, что активация taproot пройдет гладко, но мы призываем биржи и всех, кто будет принимать значительные суммы в районе блока 709 632, либо обновить свою ноду, либо быть готовыми временно повысить лимит на количество подтверждений при первом появлении каких-либо признаков проблем.

Примечания

1. Когда Electrum обновился до segwit v0, разработчики потребовали, чтобы все, кто хотел получить bech32 адреса, сгенерировали новые seed-фразы. Технически это не требовалось, однако позволило авторам Electrum внедрить несколько новых функций в свой кастомный метод получения seed-значений. Одной из таких функций была возможность по номеру версии seed определять, с какими скриптами оно должно использоваться. Это позволяет безопасно отказываться от поддержки устаревших скриптов (например, в будущем может выйти версия Electrum, которая больше не поддерживает получение транзакций на legacy P2PKH-адреса).

Примерно в то же время, когда разработчики Electrum развертывали версионирование seed-значений, разработчики Bitcoin Core начали использовать дескрипторы скриптов выходов — в том числе для решения той же проблемы: для возможности безопасного отказа от поддержки устаревших скриптов. В таблице ниже приводится сравнение версионированных seed Electrum и дескрипторов Bitcoin Core с методом неопределенных скриптов (implicit scripts), ранее использовавшимся обоими кошельками и который до сих пор широко применяется в большинстве других кошельков.

Управление скриптами Первоначальный бэкап Введение новых скриптов Сканирование (пропускная способность/CPU cost) Устаревающие скрипты
Неопределенные скрипты (напр., BIP44) Seed-фраза Автоматически (действий со стороны пользователя не требуется) Необходимо перебирать список всех поддерживаемых скриптов O(n) Нет способа предупредить пользователей, что они используют неподдерживаемые скрипты
Определенные скрипты (версионированные seed) Seed-фраза (включает биты версии) Пользователь должен создать новый seed; средства либо разделяются на два отдельных кошелька, либо пользователь должен переслать их со старого кошелька на новый Нужно проверить только один шаблон скрипта, O(1) Пользователи предупреждаются о неподдерживаемых скриптах
Определенные скрипты (дескрипторы) Seed-фраза и дескриптор Пользователь должен сохранить новый дескриптор Нужно проверить только реально использовавшиеся шаблоны скрипта, O(n); для нового кошелька n=1 Пользователи предупреждаются о неподдерживаемых скриптах


2. Пользователям, которые хотят получить P2TR-платеж в первом taproot-блоке, нужно сгенерировать адрес, которым они ни с кем не будут делиться, а затем создать транзакцию на этот адрес с nLockTime, установленным на 709 631. Эта транзакция может быть передана в сеть, как только будет получен блок 709 631. Опция nLockTime гарантирует, что транзакция не будет включена ни в один блок до 709 632, с которого вступают в силу правила taproot. Упражнения с новыми типами скриптов и кастомным временем блокировки может нести в себе риски, если вы не знаете точно, что делаете, поэтому, пожалуйста, будьте осторожны.

3. Отправители могут рандомизировать платежные маршруты и создавать очень извилистые пути платежа, пытаясь запутать анализ корреляции HTLC, но это имеет и свои недостатки:

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


4. Говоря о неопубликованных каналах, нужно помнить, что для танго нужны двое, и если неопубликованный канал закрыт, а затем один участник (скажем, провайдер LN-сервиса) использует оставшиеся средства для опубликованного канала, то блокчейн-эксплорер может предположить, что источником этих средств с некоторой вероятностью был закрытый неопубликованный канал.

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

6. Если известно заранее, вы можете предварительно подписать транзакцию расхода с определенным nSequence, но тогда вам вообще не нужен альтернативный путь расходования с «активными» ключами. Кроме того, обычно в момент получения монет пользователь не знает, как именно он собирается их потратить.

 


Подписывайтесь на BitNovosti в Telegram!
Делитесь вашим мнением об этой статье в комментариях ниже.

Источник