Одно из главных бедствий протокола Bitcoin — повторное использование адресов. Прозрачность и распределенность сети делает эту практику опасной для конфиденциальности пользователей. Чтобы избежать связанных с этим проблем, рекомендуется для получения каждого нового платежа использовать новый пустой адрес […]
«Он слишком крупный, — сказали они все, и индийский петух, который, казалось, родился со шпорами и считал себя императором, надулся, как судно со всеми поднятыми парусами, и пошел прямо на него с красными от великой ярости глазами. Бедный утенок не знал, остановиться ли ему или идти: ему было горько оттого, что все утки двора презирали его».
Одно из главных бедствий протокола Bitcoin — повторное использование адресов. Прозрачность и распределенность сети делает эту практику опасной для конфиденциальности пользователей. Чтобы избежать связанных с этим проблем, рекомендуется использовать новый пустой адрес для получения каждого нового платежа, что в некоторых случаях может быть затруднительно.
Этот компромисс стар, как сама уайтпейпер Накамото. Уже в ней Сатоши предупреждал о рисках повторного использования адресов:
«В качестве дополнительной меры безопасности для каждой транзакции следует использовать новую пару ключей, чтобы они не были связаны с общим владельцем».
Существует множество решений для получения нескольких платежей без переиспользования адреса, каждое со своими компромиссами и недостатками. Одно из них — BIP47, предложение по реализации в Биткойне многоразовых платежных кодов, разработанное Юстусом Ранвье и опубликованное еще в 2015 году. Цель — позволить проводить несколько транзакций с одним и тем же пользователем без повторного использования адреса.
Первоначально это предложение было очень холодно принято частью сообщества, и так и не было добавлено в Bitcoin Core. До сих пор некоторые программы предпочитают внедрять его самостоятельно. Так, Samourai Wallet разработал собственную реализацию BIP47: PayNym. Сегодня эта реализация доступна, очевидно, в Samourai Wallet для смартфонов и Sparrow Wallet для ПК.
Со временем Samourai стали развивать и новые функции, непосредственно связанные с PayNym. К сегодняшнему дню они предлагают уже целую экосистему инструментов для оптимизации конфиденциальности пользователей на основе PayNym и BIP47.
В этой статье я расскажу подробно о принципах BIP47 и PayNym, механизмах работы этих протоколов и некоторых практических приложениях, которые из них следуют. Я здесь буду говорить только о первой версии BIP47, той, что сейчас используется для PayNym, однако версии 2, 3 и 4 работают практически таким же образом.
Единственное существенное различие заключается в транзакции уведомления. В v1 для уведомления используется простой адрес с OP_RETURN, в v2 – multisig-скрипт (bloom-multisig) с OP_RETURN, а в v3 и v4 — просто multisig-скрипт (cfilter-multisig). Поэтому описываемые в этой статье механизмы, включая криптографические методы, применимы ко всем четырем версиям. На сегодня в реализациях PayNym в Samourai и Sparrow Wallet используется первая версия BIP47.
Навигация:
Содержание:
Проблема повторного использования адресов
Адрес получения используется для приема входящих биткойн-транзакций. Он генерируется из открытого ключа путем хеширования и применения к нему определенного формата. Это позволяет для каждого входящего платежа создавать новое условие расходования средств, изменяя его владельца.
Кроме того, вы наверняка уже слышали от опытных и информированных биткойнеров о том, что адреса получения предназначены для одноразового использования, и потому для каждого нового входящего платежа необходимо генерировать новый адрес. Ладно, но почему так?
В принципе, прямой угрозы вашим средствам повторное использование адресов не несет. Использование эллиптической криптографии позволяет доказать сети, что вы владеете закрытым ключом, без раскрытия самого ключа. Так что вы можете заблокировать на одном адресе несколько UTXO и потратить их в разное время. Это не откроет никому доступ к вашим средствам, если только вы не раскроете свой закрытый ключ, связанный с этим адресом. Но повторное использование адресов создает проблему с точки зрения конфиденциальности.
Как уже упоминалось выше, прозрачность и распределенность сети Bitcoin подразумевает, что любой пользователь, имеющий доступ к узлу сети, может наблюдать за всеми транзакциями платежной системы. Как результат, он может видеть и балансы адресов. Сатоши Накамото упоминал о возможности генерировать новые пары ключей — а значит, и новые адреса — для каждого нового платежа, поступающего в кошелек. Цель состоит в том, чтобы иметь дополнительную защиту — своего рода брандмауэр — на случай связывания идентификационных данных пользователя с одной из пар его ключей.
Сегодня, с развитием специализирующихся в блокчейн-анализе компаний и распространением на крипторынке практик KYC, генерирование новых пустых адресов для каждой новой транзакции является уже не дополнительной мерой безопасности, но обязательной мерой для каждого, кто хоть минимально беспокоится о собственной конфиденциальности.
Стремление к приватности — это не комфорт или фантазия биткойнера-максималиста. Этот параметр напрямую влияет на вашу личную безопасность и безопасность ваших средств. Приведу очень конкретный пример:
Повторное использование адресов позволяет наблюдателю установить неоспоримую связь между различными вашими UTXO, и иногда это значит — между вашей личностью и всем балансом вашего биткойн-кошелька.
Именно по этой причине большинство биткойн-кошельков автоматически генерируют новый адрес получения всякий раз, когда вы нажимаете кнопку «Получить». Поэтому для простого пользователя некастодиального кошелька необходимость использовать новые пустые адреса часто не доставляет больших неудобств. Однако для онлайн-бизнеса, биржи или кампании по сбору средств это ограничение может быстро стать неуправляемым.
Для таких организаций существует множество решений, каждое со своими преимуществами и недостатками, но на сегодняшний день и как мы увидим далее, BIP47 действительно выделяется из остальных.
Проблему повторного использования адресов в Биткойне не следует недооценивать. Как видно из приведенного ниже графика с oxt.me, общая доля повторного использования адресов пользователями Биткойна в настоящее время составляет ~50%:
Большая часть таких случаев повторного использования приходится на биржи, которые при этом руководствуются соображениями простоты и эффективности. И на сегодняшний день BIP47 является наилучшим решением для пресечения этого явления на биржах. Переход биржевых кошельков на этот стандарт позволил бы значительно снизить общий уровень повторного использования адресов, не создавая больших сложностей для этих субъектов сети. Измерение общего показателя по сети в данном случае совершенно уместно. Действительно, переиспользование адреса является проблемой не только для его обладателя, но и для всех, кто отправляет транзакции на этот адрес. Утрата конфиденциальности в Биткойне действует как вирус, распространяясь от пользователя к пользователю. Отслеживание общего показателя для всех транзакций сети позволяет нам осознать масштабы явления.
Принципы работы BIP47 и PayNym
Цель BIP47 состоит в том, чтобы предложить пользователям простой способ получать большое количество платежей без повторного использования адресов. Принцип его работы основан на использовании многоразового платежного кода.
Протокол позволяет отправлять множество платежей на один многократно используемый платежный код без необходимости для получателя передавать новый пустой адрес для каждой новой транзакции.
Пользователь может свободно публиковать такой платежный код в социальных сетях или на сайте без риска потери конфиденциальности, в отличие от классического биткойн-адреса или открытого ключа.
Для совершения обмена обоим пользователям необходимо иметь биткойн-кошелек с поддержкой BIP47, как, например, PayNym в Samurai или Sparrow Wallet. Связывание платежных кодов двух пользователей позволит установить между ними секретный канал. Для этого отправителю понадобится выполнить транзакцию-уведомление в блокчейне Биткойна; далее я расскажу об этом подробнее.
Связывание платежных кодов двух пользователей создает совместный секрет, позволяющий генерировать большое количество уникальных адресов получения BTC (2^32, если быть точным). Таким образом, в действительности платеж с BIP47 отправляется не на платежный код, а на вполне классического вида адреса, генерируемые из платежных кодов протагонистов.
То есть платежный код работает как виртуальный идентификатор, полученный из seed-значения кошелька. В структуре деривации HD-кошелька платежный код находится на глубине 3, на уровне счетов кошелька.
Его цель деривации отмечена как 47′ (0x8000002F), от BIP47. Путь деривации многоразового платежного кода будет, например, таким:
m/47'/0'/0'/
И для примера того, как выглядит сам платежный код, вот мой:
PM8TJSBiQmNQDwTogMAbyqJe2PE2kQXjtgh88MRTxsrnHC8zpEtJ8j7Aj628oUFk8X6P5rJ7P5qDudE4Hwq9JXSRzGcZJbdJAjM9oVQ1UKU5j2nr7VR5
Он также может быть закодирован в QR-код для облегчения коммуникации:
Что касается PayNym-ботов — картинок с роботами, которые можно встретить в криптотвиттере, — то это просто визуальные представления вашего платежного кода, сгенерированные Samourai Wallet. Они создаются с помощью хеш-функции, что делает каждое такое изображение уникальным. Вот так выглядит мой, с идентификатором:
+throbbingpond8B1
Эти «боты» не имеют реального технического применения. Они лишь облегчают взаимодействие между пользователями, создавая виртуальную визуальную идентичность.
Для пользователя процесс платежа по BIP47 через PayNym выглядит очень просто. Допустим, Алиса хочет отправить несколько платежей Бобу:
- Боб передает ей любым способом свой QR-код или непосредственно многоразовый платежный код. Он может разместить его в открытом доступе на своем сайте, в социальных сетях или отправить его в личных сообщениях.
- Алиса открывает кошелек Samurai или Sparrow и сканирует либо вставляет платежный код Боба.
- Алиса включает отслеживание PayNym Боба, нажимая «Follow». Эта операция не записывается в блокчейн и совершенно бесплатна.
- Алиса устанавливает-соединение между своим PayNym и PayNym Боба, нажимая «Connect». Эта операция выполняется ончейн, и Алиса должна заплатить комиссию за транзакцию, а также фиксированную комиссию Samourai в размере 15 000 сатоши за предоставление услуги. Этот шаг называется «транзакцией уведомления».
- После подтверждения транзакции уведомления Алиса может создать платежную транзакцию по BIP47 в адрес Боба. Его кошелек при этом автоматически сгенерирует новый пустой адрес получения, закрытый ключ для которого есть только у Боба.
Транзакция уведомления, т.е. установление соединения между вашим PayNym и PayNym получателя, является обязательным предварительным шагом для осуществления BIP47-платежей. С другой стороны, как только это будет сделано, отправитель сможет совершить множество (2^32) платежей получателю, не беспокоясь о повторном использовании адресов и без необходимости в повторной транзакции уведомления.
Как видите, есть две раздельные операции, позволяющие установить соединение между PayNym пользователей: Follow и Connect. Операция установления соединения («Connect») соответствует транзакции уведомления по BIP47, которая представляет собой простую биткойн-транзакцию с определенной информацией, передаваемой в OP_RETURN выходе. Она помогает установить зашифрованное соединение между двумя пользователями для последующего создания общего секрета, необходимого для генерации новых пустых адресов для получения BTC.
С другой стороны, операция включения отслеживания («Follow» или «Link») позволяет установить соединение между пользователями в Soroban, зашифрованном протоколе связи на основе Tor, специально разработанном командами Samourai.
Резюмируя:
Чтобы установить полноценное соединение между двумя PayNym, отправителю сначала нужно «зафолловить» PayNym получателя.
Инструкции: использование PayNym
Ознакомившись с теорией, давайте вместе пройдемся по практическому использованию. Идея приведенных ниже инструкций состоит в том, чтобы связать мой PayNym в Sparrow Wallet с другим моим PayNym в Samourai Wallet. В первом руководстве я показываю, как провести транзакцию с использованием многоразового платежного кода из Samourai в Sparrow Wallet, во втором — всё то же самое, но из Sparrow в Samourai.
Всю эту демонстрацию я выполнял в тестовой сети, это не настоящие биткойны.
Построение BIP47-транзакции в Samourai Wallet
Для начала вам, очевидно, понадобится приложение Samourai Wallet. Его можно установить из Google Play Store или непосредственно из APK-файла, доступного на официальном сайте Samourai.
После инициализации кошелька, если вы еще этого не сделали, сгенерируйте свой PayNym, нажав на (+) в правом нижнем углу и выбрав «PayNym».
Первым шагом к осуществлению BIP47-платежей будет получение многоразового платежного кода нашего получателя. Тогда мы сможем его зафолловить, а потом установить соединение:
https://video.wixstatic.com/video/23ab18_a8d44d8e844c4914a458628c98747f20/1080p/mp4/file.mp4
После подтверждения транзакции уведомления я смогу конфиденциально отправлять множество транзакций своему получателю. Каждая транзакция автоматически будет отправляться на новый пустой адрес, ключи к которому есть у получателя. Последнему не нужно совершать никаких действий, все рассчитывается на моей стороне.
Вот как можно сделать BIP47-транзакцию в Samourai Wallet:
https://video.wixstatic.com/video/23ab18_6bfa9190e89e49afbcfe2442cf9c2710/1080p/mp4/file.mp4
Построение BIP47-транзакции в Sparrow Wallet
Для этого, очевидно, вам понадобится установить приложение Sparrow. Оно доступно только для компьютера. Можно загрузить его с официального сайта.
Не забудьте перед установкой проверить подпись разработчика и целостность загруженного ПО.
Создайте кошелек и запросите свой PayNym, нажав на «Show PayNym» в меню «Tool» верхней панели:
Далее вам будет нужно привязать («Follow») свой PayNym к PayNym получателя и установить соединение между ними. Для этого введите многоразовый платежный код в окне «Find Contact», зафолловите его, затем выполните транзакцию уведомления, нажав «Link Contact»:
После подтверждения транзакции уведомления можно будет отправлять платежи на многоразовый платежный код получателя. Вот как это сделать:
https://video.wixstatic.com/video/23ab18_0e25345351f744d098987e695e6859c3/720p/mp4/file.mp4
Теперь, ознакомившись с практическим использованием PayNym, давайте разберемся, как эти механизмы работают и какие криптографические методы в них используются.
Как работает BIP47
Многоразовый платежный код
Как уже говорилось выше, во второй части этой статьи, многоразовый платежный код находится на глубине 3 HD-кошелька. Его в чем-то можно сравнить с xpub — как по расположению и структуре, так и по его роли.
80-битный платежный код состоит из следующих частей:
Так выглядит шестнадцатеричное представление моего многоразового платежного кода, показанного в предыдущей части:
0x010002a0716529bae6b36c5c9aa518a52f9c828b46ad8d907747f0d09dcd4d9a39e97c3c5f37c470c390d842f364086362f6122f412e2b0c7e7fc6e32287e364a7a36a00000000000000000000000000
Затем необходимо добавить байт префикса «P», чтобы можно было сразу определить, что мы имеем дело с платежным кодом. Этот байт — 0x47.
0x47010002a0716529bae6b36c5c9aa518a52f9c828b46ad8d907747f0d09dcd4d9a39e97c3c5f37c470c390d842f364086362f6122f412e2b0c7e7fc6e32287e364a7a36a00000000000000000000000000
Наконец, мы вычисляем контрольную сумму этого платежного кода с помощью HASH256, то есть получаем двойной хеш с помощью функции SHA256. Извлекаем первые четыре байта полученного конденсата и конкатенируем их в конец.
0x47010002a0716529bae6b36c5c9aa518a52f9c828b46ad8d907747f0d09dcd4d9a39e97c3c5f37c470c390d842f364086362f6122f412e2b0c7e7fc6e32287e364a7a36a00000000000000000000000000567080c4
Платежный код готов, осталось только преобразовать его в Base58:
PM8TJSBiQmNQDwTogMAbyqJe2PE2kQXjtgh88MRTxsrnHC8zpEtJ8j7Aj628oUFk8X6P5rJ7P5qDudE4Hwq9JXSRzGcZJbdJAjM9oVQ1UKU5j2nr7VR5
Можно заметить, что эта конструкция сильно напоминает структуру расширенного открытого ключа типа xpub.
В этом процессе для получения платежного кода мы использовали сжатый открытый ключ и строковый код. Эти два элемента являются результатом детерминированной и иерархической деривации из seed-значения кошелька по следующему пути: m/47’/0’/0’/.
Конкретно, чтобы получить открытый ключ и цепной код многоразового платежного кода, мы вычислим главный закрытый ключ по seed-значению, а затем получим дочернюю пару с индексом 47 + 2^31 (усиленная деривация). Затем мы дважды получаем дочерние пары с индексом 2^31 (усиленная деривация).
Криптографический метод: Elliptic-Curve Diffie-Hellman (ECDH)
Криптографический метод, используемый в основе BIP47, — ECDH (Elliptic-Curve Diffie-Hellman = обмен ключами Диффи – Хеллмана на эллиптических кривых). Это вариация классического протокола обмена ключами Диффи – Хеллмана.
Протокол Диффи – Хеллмана в своей первой версии был представлен в 1976 году и позволяет двум людям, обмениваясь информацией по незащищенному каналу связи, безопасно определить общий секрет на основе двух пар ключей (открытого и закрытого).
Этот общий секрет (красный ключ) затем может быть использован для выполнения других задач. В основном этот общий секрет может использоваться для шифрования и дешифрования сообщений в незащищенной сети:
Для успешного обмена, протокол Диффи – Хеллмана использует для вычисления общего секрета модульную арифметику. В доступной форме схему его работы можно описать так:
В этой упрощенной наглядной схеме коричневый цвет представляет собой секрет, которым поделились друг с другом Алиса и Боб. Ну и в этом примере нам надо представить, что злоумышленнику невозможно разделить оранжевый и голубой цвета, чтобы определить секретные цвета Алисы и Боба.
Теперь давайте представим, как это работает на самом деле. На первый взгляд, алгоритм Диффи – Хеллмана кажется сложным для понимания. На самом деле принцип его работы чуть ли не детский. Прежде чем подробно описать этот механизм, напомню два математических понятия, которые нам для этого понадобятся (и используемые также во многих других криптографических методах).
- Простое число: натуральное число, которое делится без остатка только на два делителя: 1 и само себя. Например, число 7 является простым, потому что оно делится без остатка только на 1 и на 7 (на само себя). А число 8 простым не является, потому что оно делится без остатка на 1, 2, 4 и 8. То есть оно имеет не два, а четыре целочисленных положительных делителя.
- «Модуль», или остаток от деления (обозначается как «mod» или «%»): математическая операция с двумя целыми числами, позволяющая вернуть остаток от евклидова деления первого числа на второе. Например, 16 mod 5 равно 1.
Обмен ключами Диффи – Хеллмана между Алисой и Бобом происходит следующим образом:
# A равно g в степени a по модулю p: A = g^a % p # B равно g в степени b по модулю p: B = g^b % p
# z равно B в степени a по модулю p: z = B^a % p
z = B^a % p z = (g^b)^a % p # В соответствии с правилами расчета степеней: (x^n)^m = x^nm # Так что мы имеем: z = g^ba % p
# z равно A степени b по модулю p: z = A^b % p # Так что мы имеем: z = (g^a)^b % p z = g^ab % p z = g^ba % p
Алиса и Боб находят совершенно одинаковое значение z. Это число представляет собой их общий секрет, то есть эквивалент коричневого цвета в предыдущей популярной схеме. Они могут использовать этот общий секрет для шифрования сообщения между ними в незащищенной сети.
Злоумышленник, узнавший значения p, g, A и B, не сможет вычислить a, b или z. Для этого понадобилось бы провести вычисление, обратное возведению в степень. Это значение невозможно получить иначе как простым перебором вариантов, поскольку мы работаем с конечным полем. Это эквивалентно вычислению дискретного логарифма, т.е. обратного показателя экспоненты в конечной циклической группе.
Таким образом, если выбрать достаточно большие значения a, b и p, то реализация протокола Диффи – Хеллмана будет безопасна. Как правило, при параметрах в 2048 бит (600-значное число в десятичной системе) проверка всех возможностей для a и b считается химерической задачей. На сегодняшний день при числах такого порядка этот алгоритм считается безопасным.
Именно на этом уровне и лежит основной недостаток протокола Диффи – Хеллмана: чтобы алгоритм был безопасным, в нем необходимо использовать большие числа. Поэтому сегодня мы предпочитаем использовать ECDH, вариант алгоритма Диффи – Хеллмана, использующий в расчетах алгебраическую кривую, в данном случае эллиптическую. Это позволяет работать с гораздо меньшими числами, сохраняя при этом эквивалентный уровень безопасности, и, следовательно, сократить ресурсы, необходимые для вычислений и хранения.
Общий принцип работы алгоритма остается прежним. Но вместо того чтобы использовать случайное число a и A, вычисляемое из него через модульное возведение в степень, мы будем использовать пару ключей, созданных на эллиптической кривой. И вместо того чтобы полагаться на дистрибутивность оператора возведения в степень, мы будем использовать групповой закон эллиптических кривых, а точнее, ассоциативность этого закона.
Грубо говоря, закрытый ключ — это случайное число от 1 до n-1 (где n — порядок кривой), а открытый ключ — это единственная точка на кривой, определяемая закрытым ключом путем добавления и удвоения точек из генерирующей точки, так что:
K = k·G
Где K — открытый ключ, k — закрытый ключ, а G — генерирующая точка.
Одно из свойств этой пары ключей заключается в том, что очень легко определить K, зная k и G, но на сегодня невозможно определить k, зная K и G: это односторонняя функция.
Другими словами, можно легко вычислить открытый ключ, зная закрытый, но невозможно вычислить закрытый ключ на основе открытого ключа. Эта безопасность, опять же, основана на невозможности вычисления дискретного логарифма.
Поэтому мы будем использовать это свойство, чтобы адаптировать наш алгоритм Диффе – Хеллмана. Тогда принцип работы ECDH будет выглядеть следующим образом:
Ka = ka·G
Kb = kb·G
(x,y) = ka·Kb
(x,y) = kb·Ka
Они получают один и тот же общий секрет, потому что:
(x,y) = ka·Kb = ka·kb·G = kb·ka·G = kb·Ka
Потенциальный злоумышленник, наблюдающий за незащищенной публичной сетью, сможет получить только открытые ключи Алисы и Боба, а также параметры выбранной кривой. Как я уже объяснял выше, рассчитать закрытые ключи по этим двум фрагментам информации на сегодня невозможно, поэтому злоумышленник не может получить доступ к секрету.
ECDH — это алгоритм, позволяющий обмениваться ключами. Он часто используется для определения протокола наряду с другими криптографическими методами. Например, ECDH используется в основе Transport Layer Security (TLS), протокола шифрования и аутентификации, используемого на транспортном уровне интернета. TLS использует для обмена ключами ECDHE, вариант ECDH, в котором ключи являются эфемерными, чтобы обеспечить постоянную конфиденциальность. В дополнение к ECDHE, TLS использует также алгоритм аутентификации наподобие ECDSA, алгоритм шифрования типа AES и хеш-функцию типа SHA256.
TLS определяет, в частности, букву «s» в названии «https», а также состояние маленького замочка, который вы видите в начале строки поиска своего интернет-браузера, которые сигнализируют вам о том, что ваше интернет-соединение с данным сайтом зашифровано. Так что вы используете ECDH и читая эту статью, как, по-видимому, используете его ежедневно, даже не осознавая этого.
Транзакция уведомления
Как мы уже выяснили в предыдущей части, ECDH — это вариант протокола обмена Диффи – Хеллмана с использованием пар ключей, определенных на эллиптической кривой. Это хорошо, что пары ключей соответствуют этому стандарту, ведь у нас есть наши биткойн-кошельки!
Таким образом, идея заключается в использовании пар ключей иерархических детерминированных биткойн-кошельков двух заинтересованных сторон для создания общих и эфемерных секретов между ними. В рамках BIP47 мы используем ECDHE (Elliptic Curve Diffie-Hellman Ephemeral).
В первый раз ECDHE используется в BIP47 для передачи платежного кода от отправителя получателю. Это та самая транзакция уведомления. Действительно, для BIP47 необходимо, чтобы каждая из двух сторон (отправитель и получатель платежей) знали платежный код другой стороны. Это понадобится для получения эфемерных открытых ключей и, соответственно, новых пустых адресов получения.
До этого обмена отправитель логически уже знает платежный код получателя: он мог быть опубликован на сайте или где-то в социальных сетях. Но получатель не обязательно знает платежный код отправителя. Его необходимо передать получателю, иначе тот не сможет вычислить свои эфемерные ключи, а значит, и получить доступ к отправленным ему биткойнам. Передать ему платежный код отправителя можно и офчейн, с помощью любой другой системы связи, но это создаст проблему в случае восстановления кошелька из seed-значения.
Действительно, как я уже упомянул, BIP47-адреса нельзя получить из seed-значения получателя (в противном случае можно было бы использовать один из его xpub напрямую), они являются результатом вычисления на основе двух платежных кодов: получателя и отправителя. Поэтому, если получатель потеряет свой кошелек и попытается восстановить его из seed-значения, он обязательно должен будет иметь все платежные коды людей, которые отправили ему биткойны через BIP47.
Так что BIP47 легко можно было бы использовать и без этой транзакции уведомления, но тогда каждому пользователю пришлось бы хранить резервную копию платежных кодов своих пиров. И это будет оставаться нежизнеспособным вариантом до тех пор, пока не будет найден простой и надежный способ выполнения, хранения и обновления таких бэкапов. Так что при нынешнем положении вещей выполнение транзакции уведомления является практически обязательным.
В дополнение к сохранению платежных кодов, транзакция уведомления, как следует из названия, служит также для информирования получателя об открытии платежного тоннеля.
Прежде чем переходить к объяснению технической стороны того, как работает транзакция уведомления, я хочу рассказать немного о модели сохранения конфиденциальности в BIP47. Использование BIP47 в дальнейшем оправдывает необходимые приготовления с выполнением этой первоначальной транзакции и созданием платежного тоннеля.
Сам по себе платежный код не несет риска потери конфиденциальности. В отличие от классической модели адресов Биткойна, предполагающей по замыслу автора разрыв взаимосвязи между личностью пользователя и транзакциями, включая сохранение анонимности открытых ключей, платежный код можно напрямую связывать с личностью его владельца. Очевидно, что это не обязательное условие, но и никакого ущерба конфиденциальности транзакций пользователей наличие этой связи не несет.
Платежный код нельзя вычислить из адресов, используемых для получения BIP47-платежей. Вместо этого, адреса получаются путем применения ECDHE с дочерними ключами платежных кодов обеих сторон.
Поэтому платежный код сам по себе не несет прямого риска потери конфиденциальности, поскольку на его основе можно вычислить только адрес уведомления. Из этого адреса можно извлечь некоторую информацию, но узнать, с кем вы совершаете транзакции, как правило, невозможно.
Поэтому так важно поддерживать это строгое разделение между платежными кодами пользователей. С этой точки зрения начальный этап передачи кода является критически важным моментом для обеспечения конфиденциальности платежей и в то же время обязательным для правильного функционирования протокола. Если один из двух платежных кодов может быть опубликован в общем доступе (например, на веб-сайте), то второй код, то есть платежный код отправителя, не должен быть связан с первым.
Допустим, я хочу настроить с BIP47 регулярные пожертвования на движение мирного протеста в Канаде:
Как я могу передать им свой платежный код? Если я отправлю его по обычным средствам связи, может произойти утечка, и я рискую быть попасть на радары контролирующих органов как негодяй, поддерживающий движения мирного протеста.
Транзакция уведомления — конечно, не единственное возможное решение для конфиденциальной передачи получателю платежного кода отправителя, но на данный момент она прекрасно справляется с этой задачей, применяя несколько уровней безопасности.
На схеме ниже красными линиями обозначены потоки информации, которые должны быть нарушены, а черными стрелками — неоспоримые связи, которые может установить сторонний наблюдатель.
В действительности для классической модели конфиденциальности Биткойна зачастую сложно полностью прервать поток информации между парой ключей и пользователем, особенно при удаленном совершении транзакций. Например, в случае кампании по сбору средств получатель должен будет раскрыть свой адрес или открытый ключ где-то на сайте или в социальных сетях. Собственное использование BIP47 — то есть с транзакцией уведомления — позволяет решить эту проблему благодаря ECDHE и уровню шифрования, который мы еще рассмотрим.
Очевидно, что на уровне эфемерных открытых ключей, полученных в результате объединения двух платежных кодов, классическая модель конфиденциальности биткойна по-прежнему соблюдается. Эти две модели взаимозависимы. Здесь я лишь хочу подчеркнуть, что, в отличие от использования для получения биткойнов классического открытого ключа, при связывании с личностью платежного кода ущерба для конфиденциальности не возникает, поскольку информационная связь «Боб совершает транзакцию с Алисой» нарушается в другой момент. Платежный код используется для генерации адресов, но на основе исключительно ончейн-данных платежную BIP47-транзакцию невозможно связать с платежными кодами, использованными для ее построения.
Построение транзакции уведомления
Теперь давайте подробно рассмотрим, как работает эта транзакция уведомления. Допустим, Алиса хочет отправить Бобу деньги с помощью BIP47. В моем примере Алиса будет отправителем, а Боб — получателем. Боб опубликовал свой платежный код на сайте, так что Алисе он уже известен.
1. Алиса вычисляет общий секрет с ECDH:
a
B = b·G
S = a·B
f = HMAC-SHA512(o, x)
2. Алиса приводит свой личный платежный код к основанию 2 (в двоичный вид).
3. Этот коэффициент ослепления используется как ключ для выполнения симметричного шифрования своего платежного кода. В качестве алгоритма шифрования используется просто XOR. Проведенная операция сопоставима с шифром Вернама (его еще называют «одноразовым блокнотом»):
f = f1 || f2
x' = x XOR f1 c' = c XOR f2
Прежде чем продолжить техническое описание нашей транзакции уведомления, давайте ненадолго остановимся на этой операции XOR. XOR — это логический оператор битового уровня, основанный на булевой алгебре. Из двух операндов в битах он возвращает 1, если биты одного ранга различаются, и 0, если биты одного ранга равны. Так выглядит таблица истинности XOR в соответствии со значениями операндов D и E:
Например:
0110 XOR 1110 = 1000
Или:
010011 XOR 110110 = 100101
С ECDH использование XOR в качестве уровня шифрования особенно логично. Во-первых, благодаря этому оператору шифрование является симметричным. Это позволяет получателю расшифровывать платежный код с помощью того же ключа, который использовался для шифрования. Ключ шифрования и дешифрования рассчитывается на основе общего секрета с помощью ECDH.
Эта симметрия возможна благодаря свойствам коммутативности и ассоциативности оператора XOR:
# Другие свойства: -> D ⊕ D = 0 -> D ⊕ 0 = D # Коммутативность: D ⊕ E = E ⊕ D # Ассоциативность: D ⊕ (E ⊕ Z) = (D ⊕ E) ⊕ Z = D ⊕ E ⊕ Z # Симметрия: If: D ⊕ E = L Тогда: D ⊕ L = D ⊕ (D ⊕ E) = D ⊕ D ⊕ E = 0 ⊕ E = E -> D ⊕ L = E
Этот метод шифрования очень похож на шифр Вернама («одноразовый блокнот»), единственный известный на сегодня алгоритм шифрования, обладающий безусловной (т.е. абсолютной) безопасностью. Для того чтобы шифр Вернама обладал этим свойством, ключ шифрования должен быть совершенно случайным, иметь тот же размер, что и сообщение, и использоваться только один раз. В методе шифрования, используемом здесь для BIP47, ключ действительно имеет тот же размер, что и сообщение, коэффициент ослепления имеет такой же размер, как конкатенация абсциссы открытого ключа с цепным кодом многоразового платежного кода. Этот ключ шифрования используется только один раз. С другой стороны, этот ключ не является совершенно случайным, поскольку он получен с HMAC. Это псевдослучайное значение. Так что это не шифр Вернама, но метод к нему приближается.
Давайте вернемся к построению нашей транзакции уведомления:
4. Итак, Алиса на текущий момент имеет свой платежный код с зашифрованной полезной нагрузкой. Она создаст и транслирует транзакцию со своим открытым ключом «A» на входе, выходом на адрес уведомления Боба и выходом OP_RETURN, состоящим из ее платежного кода с зашифрованной полезной нагрузкой. Это транзакция уведомления.
OP_RETURN — это опкод, т.е. скрипт, который позволяет пометить выход биткойн-транзакции как недействительный. Сегодня он используется для распространения или записи информации в блокчейн Биткойна. Он может хранить до 80 байт данных, которые записываются в блокчейн и, следовательно, видны всем остальным пользователям.
Как мы видели в предыдущей части, протокол Диффи – Хеллмана используется для создания общего секрета между двумя пользователями, обменивающимися данными по незащищенной сети и потенциально под наблюдением злоумышленников. В BIP47 ECDH используется для коммуникации через сеть Bitcoin, которая по своей природе прозрачна и за которой могут наблюдать все интересующиеся, включая множество потенциальных злоумышленников. Общий секрет, рассчитанный через обмен ключами по методу Диффи – Хеллмана на эллиптической кривой, затем используется для шифрования передаваемой секретной информации: платежного кода отправителя (Алисы).
Вот диаграмма из BIP47, иллюстрирующая этот процесс:
Если сопоставить эту схему с моим описанием, то:
И резюмируем шаги для выполнения транзакции уведомления, которые мы только что рассмотрели:
Чтобы более подробно понять, как это работает, включая использование OP_RETURN, давайте рассмотрим реальную транзакцию уведомления. Я сделал такую транзакцию в тестовой сети, к ней можно перейти по этой ссылке.
TXID:
0e2e4695a3c49272ef631426a9fd2dae6ec3a469e3a39a3db51aa476cd09de2e
Мы видим, что эта транзакция имеет один вход и 4 выхода:
Наибольший интерес, очевидно, представляет выход 0 с OP_RETURN. Давайте рассмотрим его подробнее:
Здесь мы видим скрипт выхода в шестнадцатеричном формате:
6a4c50010002b13b2911719409d704ecc69f74fa315a6cb20fdd6ee39bc9874667703d67b164927b0e88f89f3f8b963549eab2533b5d7ed481a3bea7e953b546b4e91b6f50d800000000000000000000000000
В этом скрипте можно выделить несколько частей:
6a4c50010002b13b2911719409d704ecc69f74fa315a6cb20fdd6ee39bc9874667703d67b164927b0e88f89f3f8b963549eab2533b5d7ed481a3bea7e953b546b4e91b6f50d800000000000000000000000000 # Опкоды: 6a4c50 # Метаданные моего платежного кода в чистом виде: 010002 # Зашифрованная абсцисса открытого ключа моего платежного кода: b13b2911719409d704ecc69f74fa315a6cb20fdd6ee39bc9874667703d67b164 # Зашифрованный цепной код моего платежного кода: 927b0e88f89f3f8b963549eab2533b5d7ed481a3bea7e953b546b4e91b6f50d8 # Заполнение до 80 байт: 00000000000000000000000000
Из опкодов можно выделить 0x6a, обозначающий OP_RETURN, 0x4c, обозначающий OP_PUSHDATA1, и 0x50, обозначающий OP_RESERVED.
Затем идет платежный код с зашифрованной полезной нагрузкой.
Вот мой платежный код в открытом виде, использованный в этой транзакции:
# С основанием 58: PM8TJQCyt6ovbozreUCBrfKqmSVmTzJ5vjqse58LnBzKFFZTwny3KfCDdwTqAEYVasn11tTMPc2FJsFygFd3YzsHvwNXLEQNADgxeGnMK8Ugmin62TZU # С основанием 16 (HEX): 4701000277507c9c17a89cfca2d3af554745d6c2db0e7f6b2721a3941a504933103cc42add94881210d6e752a9abc8a9fa0070e85184993c4f643f1121dd807dd556d1dc000000000000000000000000008604e4db
Если мы сравним мой платежный код (в открытом виде) с OP_RETURN, то увидим, что HRP и контрольная сумма не передаются. Это нормально, т.к. эта информация предназначена для людей.
И мы можем узнать также версию (0x01), битовое поле (0x00) и четность открытого ключа (0x02). А в конце платежного кода идут просто пустые байты (0x00), заполняющие оставшийся объем до 80 байт. Все эти метаданные передаются в открытом (незашифрованном) виде.
Наконец, можно видеть, что абсцисса открытого ключа и строковый код были зашифрованы. Это полезная нагрузка платежного кода.
Получение транзакции уведомления
Теперь, когда Алиса отправила Бобу транзакцию уведомления, давайте посмотрим, как Боб ее интерпретирует.
Напомню, что Боб должен иметь доступ к платежному коду Алисы. Без этой информации, как мы увидим в следующей части, он не сможет вывести пары ключей, созданные Алисой, и, следовательно, не сможет получить доступ к своим биткойнам, полученным с использованием BIP47. На данный момент полезная нагрузка платежного кода Алисы зашифрована. Давайте теперь посмотрим, как Боб ее расшифрует.
1. Боб мониторит транзакции, создающие выходы с его адресом уведомления.
2. Обнаружив такую транзакцию, Боб анализирует ее на наличие OP_RETURN выхода, соответствующего стандарту BIP47.
3. Если первый байт полезной нагрузки OP_RETURN равен 0x01, Боб начинает поиск возможного секрета, переданного с ECDH:
A = a·G
b
S = b·A
f = HMAC-SHA512(o, x)
4. Боб интерпретирует данные OP_RETURN в транзакции уведомления как платежный код. Он с легкостью расшифрует полезную нагрузку этого потенциального платежного кода благодаря коэффициенту ослепления «f»:
x = x' XOR f1
c = c' XOR f2
5. Боб проверяет, входит ли значение открытого ключа от платежного кода Алисы в группу secp256k1. Если входит, то он интерпретирует его как действительный платежный код. В противном случае он игнорирует эту транзакцию.
Теперь, когда Боб знает платежный код Алисы, она может отправить ему до 2^32 платежей без необходимости повторно выполнять подобную транзакцию уведомления.
Почему это работает? Как Боб может определить тот же коэффициент ослепления, что и Алиса, и, следовательно, расшифровать его платежный код? Давайте подробнее проследим действие ECDH в описанном только что процессе.
Прежде всего, мы имеем дело с симметричным шифрованием. Это означает, что ключ шифрования и ключ дешифрования — это одно и то же значение. В транзакции уведомления этот ключ является коэффициентом ослепления (f = f1 || f2). Поэтому Алиса и Боб должны получить одно и то же значение f без его прямой передачи, поскольку злоумышленник может украсть его и расшифровать секретную информацию.
Этот коэффициент ослепления получается путем применения хеш-алгоритма HMAC-SHA512 к двум значениям: абсциссе секретной точки и UTXO, потребленному в качестве входа транзакции. Чтобы расшифровать полезную нагрузку платежного кода Алисы, Бобу необходимы два этих фрагмента информации.
Что касается UTXO входа, то Боб может его получить просто из ончейн-данных о транзакции уведомления. Для секретной точки Бобу придется использовать ECDH.
Как показано в части об алгоритме Диффи – Хеллмана, просто обменявшись своими соответствующими открытыми ключами и применив свои закрытые ключи к каждому из открытых ключей партнера, Алиса и Боб могут определить в точности одну и ту же секретную точку на эллиптической кривой. На этом механизме основана транзакция уведомления:
# Пара ключей Боба: B = b·G # Пара ключей Алисы: A = a·G # Для секретной точки S (x,y): S = a·B = a·b·G = b·a·G = b·A
Теперь, когда Боб знает платежный код Алисы, он сможет определить ее BIP47-платежи в свой адрес и вычислить закрытые ключи, блокирующие получаемые в этих транзакциях биткойны.
Если сопоставить эту схему с моим описанием, то:
И резюмируем шаги для выполнения транзакции уведомления, которые мы только что рассмотрели:
Платежная транзакция BIP47
Теперь давайте вместе рассмотрим процесс платежа с BIP47. Кратко напомню о текущем положении дел:
Прежде чем перейти к объяснению этого процесса, я думаю, важно напомнить, с каким индексом мы сейчас работаем:
Мы описываем путь деривации платежного кода следующим образом: m/47’/0’/0’/.
Следующая глубина распределяет индексы таким образом:
Каждый раз, когда Алиса хочет отправить Бобу платеж, она получает новый уникальный пустой адрес, опять же благодаря протоколу ECDH:
a
B = b·G
S = a·B
s = SHA256(Sx)
K0 = B + s·G
Получив этот принадлежащий Бобу адрес приема «K0», Алиса может построить классическую биткойн-транзакцию, выбрав UTXO из другой ветки своего HD-кошелька и потратив его на «K0» адрес Боба.
Если сопоставить эту диаграмму из BIP47 с тем, что я описал ранее, то:
И резюмируем шаги для отправки BIP47 платежа, которые мы только что рассмотрели:
Если она хочет произвести второй платеж, она воспроизводит все те же действия, но выбирает второй открытый ключ, полученный из платежного кода Боба, то есть следующий неиспользованный ключ. Тогда она получит второй принадлежащий Бобу адрес приема «K1».
Это можно повторять до 2^32 раз и получить до 2^32 новых пустых адресов приема, принадлежащих Бобу.
С точки зрения внешнего наблюдателя, отличить BIP47 платеж от обычной биткойн-транзакции теоретически невозможно. Вот пример платежной BIP47 транзакции в тестовой сети:
https://blockstream.info/testnet/tx/94b2e59510f2e1fa78411634c98a77bbb638e28fb2da00c9f359cd5fc8f87254
TXID:
94b2e59510f2e1fa78411634c98a77bbb638e28fb2da00c9f359cd5fc8f87254
Она выглядит как обычная транзакция с потребляемым входом, выходом с платежом в 210 000 сатоши и сдачей:
Получение BIP47-платежа и получение закрытого ключа
Итак, Алиса сделала свой первый BIP47-платеж на автоматически сгенерированный новый пустой адрес, принадлежащий Бобу. Теперь давайте вместе посмотрим, как Боб получает этот платеж. Мы увидим также, почему Алиса не имеет доступа к закрытому ключу от адреса, который она только что сгенерировала, и как Боб находит этот ключ, чтобы потратить биткойны, полученные в такой транзакции.
Когда Боб получает от Алисы транзакцию уведомления, он получает открытый ключ «K0» еще до того, как его корреспондент по BIP47 отправил платеж. Поэтому он следит за любыми платежами на связанный адрес. На самом деле он сразу вычислит несколько адресов, которые и будет наблюдать (K0, K1, K2, K3 …). Вот как он получает этот открытый ключ «K0»:
b
A = a·G
S = b·A
s = SHA256(Sx)
K0 = B + s·G
Получив этот открытый ключ «K0», Боб сможет получить соответствующий закрытый ключ, чтобы потратить свои биткойны. Это число может сгенерировать только он.
k0 = b + s
Благодаря групповому закону эллиптической кривой, Боб получает именно тот закрытый ключ, который соответствует открытому ключу, используемому Алисой. Так что мы имеем:
K0 = k0·G
Если сопоставить эту диаграмму из BIP47 с тем, что я описал ранее, то:
И резюмируем шаги для получения BIP47 платежа и вычисления соответствующего закрытого ключа:
Поскольку Алиса не может получить «b», закрытый ключ Боба, она не может определить k0, закрытый ключ, связанный с адресом получения BIP47 Боба.
Схематически вычисление общего секрета «S» можно представить следующим образом:
Найдя с помощью ECDH общий секрет, Алиса и Боб вычисляют открытый ключ платежа BIP47 «K0», а Боб вычисляет также соответствующий закрытый ключ «k0»:
Возврат BIP47-платежа
Поскольку Боб знает многоразовый платежный код Алисы, у него уже есть вся информация, необходимая для отправки ей возвратных платежей. Ему не придется снова связываться с Алисой, чтобы узнать какую-то дополнительную информацию. Он просто должен будет уведомить ее с помощью транзакции уведомления, в частности чтобы она могла восстановить свои BIP47-адреса из seed-значения, — и тогда он тоже сможет отправить Алисе до 2^32 платежей.
Боб сможет отправлять платежи Алисе тем же способом, каким она отправляла платежи ему. Роли при этом меняются местами:
Теперь вы знаете все принципы работы этого прекрасного платежного решения, которое собой представляет BIP47.
Производные варианты использования PayNym
Результатом реализации этого BIP47 в кошельке Samourai Wallet стали PayNym, идентификаторы, вычисленные из платежных кодов пользователей. Сегодня их полезность выходит уже далеко за рамки применения BIP47.
Команды разработчиков Samourai постепенно выстраивают целую экосистему инструментов и сервисов, основанных на PayNym пользователей. Среди них, очевидно, есть все инструменты для расходования, позволяющие оптимизировать конфиденциальность пользователя через добавление к транзакции энтропии, а значит, и возможности правдоподобного отрицания.
Использование Soroban (зашифрованной сети связи на основе Tor) совместно с PayNym позволило значительно оптимизировать пользовательский опыт при создании коллаборативных, совместных транзакций, сохранив при этом хороший уровень безопасности. Благодаря этому, Stowaway (PayJoin) и StonewallX2 транзакции можно легко осуществить без ручного проведения многочисленных обменов неподписанными транзакциями, необходимых для создания коллаборативной транзакции такого типа.
В отличие от BIP47, для использования этих инструментов достаточно просто связать PayNym(ы) через фолловинг, поскольку эти коллаборативные транзакции не требуют выполнения транзакции уведомления. Между ними нет необходимости устанавливать соединение.
Помимо этих коллаборативных транзакций, команды Samourai участвуют в разработке протокола аутентификации, связанного с PayNym, — Auth47. Этот инструмент уже работает и позволяет, например, авторизоваться по PayNym на сайтах, принимающих такой метод аутентификации. В будущем, я думаю, что помимо этой возможности аутентификации в интернете, Auth47 станет частью более глобального проекта вокруг экосистемы BIP47/PayNym/Samourai Wallet. Возможно, этот протокол будет использоваться для дальнейшей оптимизации пользовательского опыта Samourai Wallet, особенно в отношении инструментов расходования.
Мое мнение о BIP47
Очевидно, что основным недостатком BIP47 является транзакция уведомления. Это дополнительное действие, к тому же сопровождаемое комиссиями сети (за биткойн-транзакцию) и сервиса, что может вызывать раздражение у части пользователей. С другой стороны, аргумент о «спаме» блокчейна Биткойна абсолютно неприемлем. Любой, кто платит комиссию за транзакцию, должен иметь возможность записать ее в реестр, независимо от цели транзакции. Утверждать обратное — значит высказываться в пользу цензуры.
Возможно, что в будущем будут найдены другие, менее затратные решения для передачи получателю платежного кода отправителя и надежного его хранения. Но пока что транзакция уведомления остается наименее компромиссным решением.
А с учетом преимуществ BIP47, этот недостаток даже не выглядит настолько значимым. Из всех существующих предложений по решению проблемы повторного использования адресов, это, на мой взгляд, лучшее решение.
Как упоминалось выше, источником большей части повторного использования адресов являются биржи. BIP47 — единственное разумное решение, которое действительно решает эту проблему в самом ее источнике. Любое предложение по сокращению повторного использования адресов должно учитывать этот аспект и адаптировать решение под основной источник проблемы.
С точки зрения пользователя, несмотря на довольно сложный механизм работы, процесс платежа с BIP47 выглядит довольно детским. Поэтому многоразовые платежные коды могут быть довольно легко приняты даже начинающими пользователями.
С точки зрения конфиденциальности, BIP47 представляет очень большой интерес. Как я уже объяснял, рассказывая о транзакциях уведомления, платежные коды не раскрывают никакой информации о производных эфемерных адресах. Таким образом, они позволяют прервать поток информации между биткойн-транзакцией и идентификатором получателя, в отличие от традиционного использования адреса получателя.
И самое главное, реализация BIP47 в виде PayNym работает уже сейчас. В Samourai Wallet они доступны с 2016, а в Sparrow Wallet с начала этого года. Это не какой-то исследовательский эксперимент, а практическое решение, проверенное вчера и полностью работоспособное сегодня.
Надеюсь, что в будущем эти платежные коды будут приняты участниками экосистемы, поддержка их будет реализована в большем количестве кошельков и они получат распространение среди биткойнеров.
Любое действительно позитивное решение для обеспечения конфиденциальности пользователей нужно обсуждать, отстаивать и продвигать, чтобы Биткойн не превратился в площадку для централизованных игроков и инструмент правительственной слежки.
«Он думал о том, как его всюду оскорбляли и преследовали, а теперь он слышал, как все говорят о нем как о самой красивой из всех этих прекрасных птиц! И сама бузина склонила к нему свои ветви и солнце пролило такой теплый и благодатный свет! Тогда его перья распушились, стройная шея поднялась и он воскликнул от всего сердца: «Как я мог мечтать о таком счастье, когда был всего лишь гадким утенком!»»
БитНовости отказываются от ответственности за любые инвестиционные рекомендации, которые могут содержаться в данной статье. Все высказанные суждения выражают исключительно личное мнения автора и респондентов. Любые действия, связанные с инвестициями и торговлей на крипторынках, сопряжены с риском потери инвестируемых средств. На основании предоставленных данных, вы принимаете инвестиционные решения взвешенно, ответственно и на свой страх и риск.
Источник: bitnovosti.com