Готовясь к активации Taproot
Перевод серии постов от Bitcoin Optech, посвященных технической стороне подготовки к активации Taproot. Рекомендации, примеры кода, ссылки на обучающие материалы и просто чего ожидать при активации. А также ожидаемые новые функции и предположительные сроки их реализации.
(Пост дополняется сносками и ссылками)
Содержание:
- 1 Список тем:
- 2 Поддержка отправки bech32m
- 3 Имеет ли смысл использовать taproot для обычных транзакций с одной подписью?
- 4 Taproot дескрипторы
- 5 От P2WPKH к single-sig P2TR
- 6 Сохранность средств на P2TR выходах до активации и безопасный период после активации taproot
- 7 Изучайте taproot, используя его
- 8 Обзор мультиподписи
- 9 Nonce-значения мультиподписи
- 10 Адаптеры подписи (signature adaptors)
- 11 PTLC (Point Time Locked Contracts)
- 12 Lightning Network с taproot
- 13 Vault с taproot
- 14 Схемы безопасности и восстановления доступа к средствам
- 15 Тестирование в signet
- 16 Протокол для подписи универсальных сообщений по-прежнему нужен
- 17 Связывание выходов
- 18 Всегда ли нужна опция сотрудничества?
- 19 Будущие изменения консенсуса
- 20 Что произойдет при активации?
Список тем:
Поддержка отправки 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 кошельков, так и для сети в целом.
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 перечисляется также ряд отсутствующих опций, которые можно было бы добавить, чтобы дескрипторы лучше и полнее описывали ожидаемые пользовательские политики расходования:
tr()
нерасходуемый ключ, но хорошо было бы позволить кошелькам хранить это предпочтение в самом дескрипторе и вычислять нерасходуемый keypath без ущерба для приватности.multi()
и sortedmulti()
поддерживают опкод OP_CHECKMULTISIG
. Чтобы позволить выполнение пакетной проверки в taproot, мультиподписи на основе скриптов в tapscript обрабатываются несколько иначе, поэтому на сегодняшний день дескрипторам tr()
приходится указывать любые необходимые multisig опкоды через скрипт raw()
. Было бы неплохо заручиться обновленными версиями скриптов multi()
и sortedmulti()
для tapscript.tr()
. В идеале хорошо было бы иметь функцию, которая позволила бы им указать что-то вроде tr(musig(<a_key>, <b_key>, <c_key>))
, чтобы они могли сохранить всю информацию об исходном ключе и использовать ее для заполнения полей в PSBT, используемых для координации подписания.raw()
. Добавление их поддержки непосредственно в дескрипторы возможно, но может случиться так, что вместо этого поддержка будет реализована через родственный дескрипторам проект miniscript. Интеграция miniscript в Bitcoin Core еще в процессе, но мы ожидаем, что в будущем эти инновации распространятся и на другие кошельки, как это уже произошло с PSBT и дескрипторами.Кошелькам не обязательно реализовывать дескрипторы, чтобы начать использовать taproot, но те, кто это сделают, создадут лучшую основу для использования более продвинутых функций taproot впоследствии.
От P2WPKH к single-sig P2TR
Для кошельков, уже поддерживающих получение и расходование P2WPKH-выходов segwit v0, обновление до segwit v1 P2TR для single-sig транзакций должно быть довольно простым. Основные шаги выглядят так:
tr()
или если позже вы решите добавить поддержку scriptless мультиподписей (Scriptless Scripts PDF).OP_1 <tweaked_pubkey>
. Сканировать транзакции в адрес скрипта можно любым методом, который вы использовали для сканирования segwit v0 адресов, как P2WPKH.До активации 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. Эти платежи будут защищены в блоке 709 632, однако они могут быть беспрепятственно украдены любым майнером, который создаст альтернативу блоку 709 631. Если общая стоимость отправленных на P2TR биткойнов достаточно велика, то может быть оправдано попытаться добыть два блока вместо одного (подробнее в теме Fee Sniping на Bitcoin Optech).
По этой причине мы не рекомендуем генерировать адреса для P2TR до того момента, как вы будете уверены, что риск реорганизации больше неактуален. Мы считаем период в 144 блока (около одного дня) после активации достаточно консервативным, чтобы свести риски к минимуму, не задерживая чрезмерно сервисы и пользователей от использования taproot.
В двух словах:
Однако ничто из описанного здесь не отменяет приведенных выше рекомендаций о скорейшей реализации платежей на bech32m адреса. Если кто-то запрашивает платеж на P2TR адрес до того момента, который вы считаете безопасным сроком, то это их риск, а не отправителя.
Изучайте taproot, используя его
Около двух лет назад James Chiang и Elichai Turkel создали открытый репозиторий Jupyter-документов для серии воркшопов Bitcoin Optech, посвященных обучению разработчиков технологии taproot. Воркшопы в Сан-Франциско, Нью-Йорке и Лондоне, получили положительные отзывы, но возникшие позже ограничения на поездки помешали проведению новых очных семинаров.
С момента публикации этих Jupyter-документов taproot претерпел несколько изменений. Но вместе с тем поддержка taproot была добавлена в Bitcoin Core, что позволило репозиторию устранить зависимость от отдельной кастомной ветки Bitcoin Core. Разработчик Elle Mouton любезно обновил репозиторий с учетом всех этих изменений, снова превратив его в отличный способ быстро получить практический опыт работы с taproot алгоритмами и типами данных.
Документы репозитория поделены на четыре раздела:
Репозиторий содержит множество упражнений по программированию, сравнительно простых, но гарантирующих, что вы действительно усвоили представленный материал. Автор этого текста, не бог весть какой кодер, справился с прохождением за шесть часов и сожалел только о том, что не сделал этого раньше.
Обзор мультиподписи
В последней 1000 блоков по состоянию на момент написания этой части 11% всех входов транзакций содержали опкод мультиподписи. Два самых больших и непосредственных преимущества taproot проявятся, если многие из пользователей и сервисов, создающих такие транзакции, перейдут с опкодов на scriptless мультиподписи.
Первым большим преимуществом будет уменьшение размера транзакции. Мультиподписи на основе скриптов имеют тем больший размер, чем больше ключей и подписей для них требуется, в то время как сами мультиподписи имеют постоянный небольшой размер. Наименьшая эффективная политика multisig скрипта (1-из-2) требует больше места, чем политика мультиподписи, которая может подразумевать участие тысяч подписантов. Это уменьшение размера обеспечивает прямое снижение комиссий для пользователей мультиподписи и косвенное для всех пользователей за счет того, что один и тот же объем спроса на подтверждение транзакций может быть удовлетворен с использованием меньшего пространства блока.
Второе важное преимущество — это повышение приватности. Каждое использование multisig скрипта явным и определенным образом записывается в блокчейн, где наблюдатели могут использовать эти записи для формулирования обоснованных предположений об истории кошелька и текущем балансе отдельных пользователей. Например, глядя на блок 692 039, мы можем не только отличить multisig и single-sig транзакции друг от друга, но и сделать некоторые обоснованные выводы на основе размеров сетов и пороговых значений для multisig скриптов.
Для сравнения, третья сторона на основе только данных блокчейна не может сделать вывод о том, что отправитель использовал мультиподпись. Когда для расходования по keypath используется мультиподпись, это неотличимо от расходования через single-sig транзакции. Если все single-sig и multisig транзакции в блоке выше перевести в P2TR транзакции расхода по keypath, то различимы за счет своих скриптов будут лишь несколько экзотических расходований (и те в самом идеальном сценарии могли быть реализованы через keypath).
Использование мультиподписей
Нам известно о трех схемах мультиподписи на основе схемы Шнорра, разработанных специально для Биткойна, все из семейства MuSig:
Все подписанты должны согласовать между собой используемый протокол, поэтому здесь может возникнуть сетевой эффект, когда многие реализации решат использовать один и тот же протокол. Авторы предложений MuSig предполагают, что это будет MuSig2, из-за свойственного ему сочетания относительной простоты и высокой полезности.
Существует открытый и активно разрабатываемый пулл-реквест к проекту libsecp256k1-zkp для добавления поддержки MuSig2. Мы ожидаем, что базовый процесс работы с мультиподписью для большинства программ будет выглядеть примерно следующим образом:
- Кошелек каждого участника генерирует BIP32 xpub, которым они делятся с остальными участниками с помощью дескриптора скрипта выхода или иного метода (аналогично тому, как это обычно реализуется сейчас для скриптов мультиподписи).
- Затем любой из кошельков может сгенерировать общий, агрегированный открытый ключ, объединив свой pubkey на определенной BIP32 глубине с pubkey на той же глубине от всех остальных кошельков множества мультиподписи. Этот агрегированный открытый ключ можно использовать для получения P2TR платежей.
- Когда один из кошельков хочет потратить средства, он использует процесс на основе PSBT, подобный тому, что использовал бы со скриптовой мультиподписью, но теперь требуется два раунда коммуникаций между подписывающими сторонами. В первом раунде инициатор создает неподписанную транзакцию и включает в нее пару случайным образом сгенерированных nonce. Абсолютно важно, чтобы значения nonce не были получены полностью детерминированным способом, который бы мог привести к повторному использованию того же nonce для другой подписи. Инициатор отправляет PSBT с двумя nonce другим кошелькам.
- Другие кошельки получают PSBT, добавляют в нее свои пары случайных nonce и отправляют другим кошелькам или общему координатору, бездоверительным образом работающему от имени кошельков.
- Когда все кошельки получают все пары 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 в области приватности на сегодняшний день.
Хотя 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, — и посмотреть, как это улучшает приватность:
Как уже упоминалось в предыдущем разделе, схемы Шнорра позволяют легко создавать адаптеры для мультиподписей. В случае стандартных 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 в Lightning Network
PTLC позволяют реализовать множество функций, самой важной из которых для LN, как уже говорилось в предыдущей части, является декорреляция платежей без необходимости рандомизировать маршруты. Каждому узлу на пути простого (single-path) или разветвленного (multipath) маршрута может быть присвоен скаляр, который используется для подстройки каждого пересылаемого PTLC, обеспечивая декорреляцию платежей, при которой в отдельных пересылках больше не происходит утечки уникального идентификатора для каждого LN платежа.
PTLC — это не панацея против всех проблем приватности. Если наблюдающий узел видит форвардный (пересылаемый) платеж с определенным таймлоком и суммой и вскоре после этого второй наблюдающий узел видит форвардный платеж с меньшим таймлоком и чуть меньшей суммой, то очень вероятно, что эти пересылаемые платежи принадлежат к одному платежному пути, даже если их нельзя соотнести с помощью уникального идентифицирующего хеша. Однако PTLC действительно обеспечивают:
В принципе, 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-канал, — что повышает уровень ончейн приватности для неопубликованных («приватных») каналов.
Это (довольно небольшое) повышение приватности приносит пользу и опубликованным каналам тоже. Информация об опубликованных каналах распространяется по сети только до тех пор, пока они открыты, поэтому попытка поиска опубликованных каналов не даст результатов относительно существовавших ранее и уже закрытых каналов. Если наблюдатель хочет иметь данные о каждом когда-либо существовавшем опубликованном канале, он должен хранить все эти данные сам и не может полагаться на какой-либо «архивный» узел.
Кроме того, 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) проекте — это взять за основу предыдущие функции и то, сколько времени заняла их реализация.
Последняя важная функция, на мой взгляд, аналогичная по масштабу 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, платит либо:
- набору открытых ключей после относительной блокировки по времени (таймлока) или
- одному открытому ключу без каких-либо таймлоков.
Первый вариант расходования — основной, который, как ожидается, будет использоваться с более «горячими» ключами. Второй вариант расходования позволяет отменить транзакцию.
Таким образом, концепция vault идет несколько вразрез с идеей taproot о том, что большинство контрактов предусматривают «счастливый путь», в котором все участники сотрудничают через подпись (а путь оспаривания обычно содержит временные блокировки). Скорее наоборот. Для транзакции расходования необходимо использовать taproot-скрипт, поскольку он ограничен относительным таймлоком, в то время как транзакция отмены теоретически может выполняться через расходование по ключу.
Поскольку многосторонние 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.
Тестирование в 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 выход.
Эксперту или алгоритму, наблюдающими такие транзакции несложно сделать разумный вывод о том, что P2TR выход в ней — это выход для сдачи, принадлежащий самому пользователю, а значит, другой выход принадлежит получателю платежа. Это не гарантированно так, но является наиболее вероятным объяснением.
Некоторые утверждают, что многие преимущества taproot в отношении конфиденциальности не стоит пока воспринимать всерьез из-за этого вероятного временного снижения приватности в период перехода кошельков на P2TR. Многие эксперты называли такое заключение неоправданным и чрезмерным. Мы присоединяемся к мнению последних и можем также предложить несколько дополнительных контраргументов против критики по этому направлению:
Всегда ли нужна опция сотрудничества?
Оригинальное предложение taproot авторства Грегори Максвелла включало интересный принцип построения контракта:
«Почти всегда бывает так, что интересные скрипты имеют логическую ветвь верхнего уровня, которая позволяет выполнение контракта только с подписями всех сторон. Другие ветви будут использоваться только в тех случаях, когда какой-либо участник отказывается от взаимодействия. Строго говоря, я считаю, что любой контракт с фиксированным и конечным набором участников может и должен быть представлен как ИЛИ между N-of-N и любым более сложным контрактом, который вы можете захотеть представить».
С тех пор эксперты обсуждали универсальность этого принципа, за двумя известными нам возможными исключениями, связанными с временными блокировками:
Аргумент против того, чтобы всегда предоставлять опцию расхода по keypath, по-видимому, заключается в том, что бывают случаи, в которых даже все совместно действующие подписанты не доверяют в полной мере себе. Однако они готовы доверять другим людям — операторам экономических полных узлов, обеспечивающих соблюдение правил консенсуса Биткойна, — в том, чтобы те обеспечили соблюдение ограничений на расходование вместо самих подписантов.
Контраргумент состоит в том, что, по крайней мере чисто теоретически, вы можете обеспечить тот же уровень безопасности, создав расход по keypath между обычными подписантами и всеми этими операторами экономических полных нод. С практической точки зрения, вероятно, существует некое подмножество или альтернативный набор этих операторов узлов, которые могут быть добавлены в множество мультиподписи для вашего расхода по ключу и которые будут применять желаемую политику, если они доступны (если нет, вы ничего не теряете, так как по-прежнему можете использовать расход по scriptpath).
Теория теорией, но разработчикам мы рекомендуем потратить некоторое дополнительное время на то, чтобы рассмотреть возможность добавления в контракты на основе taproot расхода по keypath, даже если изначально такая опция не кажется вам необходимой.
Будущие изменения консенсуса
Пока taproot приближается к активации на блоке 709 632, мы можем уже начинать с нетерпением ожидать некоторых изменений консенсуса, о желании реализовать которые «поверх» taproot разработчики уже упоминали ранее.
OP_SUCCESSx
. Подобно OP_NOPx
(без операции), добавленным на ранних этапах истории Биткойна, OP_SUCCESSx
предназначены для замены опкодами, которые не всегда возвращают успех. Некоторые предлагаемые новые опкоды включают:
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, либо обновить свою ноду, либо быть готовыми временно повысить лимит на количество подтверждений при первом появлении каких-либо признаков проблем.
Источник: bitnovosti.com