[recovery mode] Аудит кошельков в CryptoNote

hof8key466f4lng25pcqotu0soo.png

Аудит криптовалютного кошелька — это возможность для третьей стороны («аудитора») видеть транзакции этого кошелька и рассчитывать его корректный актуальный баланс без права на трату средств.

В статье рассматриваются различные способы обеспечения такой возможности в криптовалютном протоколе CryptoNote 2.0 [1], где аудит реализован лишь частично: с помощью трекингового ключа можно распознавать входящие транзакции, но для распознавания исходящих нужен полный набор ключей.

Материал рассчитан на читателей, знакомых с темой блокчейна и «классических» криптовалют, а также с основами криптографии на эллиптических кривых.

Содержание


1. Введение
2. Базовые сведения о криптографии на эллиптических кривых
3. Учет средств и расчет баланса в CryptoNote
4. Вариант ⅓. Bytecoin Auditable Coins
  4.1. tx.version < amethyst, legacy address
  4.2. tx.version ≥ amethyst
  4.3. tx.version ≥ amethyst, legacy address
  4.4. tx.version ≥ amethyst, amethyst address
  4.5. Сравнение подписей транзакций CryptoNote и Bytecoin Amethyst
5. Вариант 2/3. Исследования аудита в CryptoNote от Anton Sokolov
6. Вариант 3/3. Аудит через ограничение на подмешивание выходов
7. Заключение
Литература

Что такое CryptoNote?


Как это ни странно, но большинство интересующихся блокчейн-технологиями ничего не слышали о CryptoNote, и это несмотря на то, что эта технология явилась основой для более чем 300 форков, самым известным из которых стал Monero.

В 2014 году в криптовалютной среде появились упоминания [2] о проекте, который назывался Bytecoin. Проект не являлся форком Bitcoin или другого открытого проекта и имел совершенно новую кодовую базу, что было крайне необычно для того времени. Его основная концепция сводилась к реализации privacy-технологии, которую называли CryptoNote. Приватность обеспечивалась двумя механизмами: стелс-адресами и подмешиванием входов с использованием кольцевой подписи (ее еще называли в то время «микшер на блокчейне»). Поскольку в то время Zcash существовал только в теории, технология оказалась весьма конкурентоспособной и вызвала большой резонанс в криптовалютном сообществе.

Вскоре группа энтузиастов, проявившая интерес к одному из первых форков этой технологии, а затем и перехватившая инициативу в этом форке, своими энергичными действиями сумела привлечь наибольшее внимание к технологии как среди сообщества так и среди инвесторов. Этот форк назывался BitMonero [3, 4], однако довольно скоро он был переименован в Monero.

В дальнейшем оба проекта — Bytecoin и Monero — развивались технологически разными путями: если Bytecoin оставался закрытым анонимным проектом, то Monero превратился в крупный community-driven проект с очень большим количеством участников и разработчиков. Тем не менее, они оба являются развитием CryptoNote технологии.

Понятие аудита и его приложения


В отличие от классического «псевдонимного» блокчейна типа Bitcoin, в котором любой желающий, сканируя блокчейн, может тривиально подсчитать балансы любого адреса, в приватном блокчейне, в частности, в CryptoNote, эта задача едва ли осуществима без дополнительных знаний. Во-первых, благодаря технологии стелс-адресов, в блокчейне вообще отсутствуют упоминания каких-либо адресов (это свойство обычно обозначается как anonymity). Во-вторых, в силу того, что благодаря кольцевой подписи вход транзакции не указывает на один конкретный выход родительской транзакции, а указывает, в общем случае, на множество вероятных выходов, отследить движение средств также не представляется возможным (это свойство называется untraceability).

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

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

Об авторе и цели публикации


Автор данного материала является одним из основных разработчиков проекта Zano — проекта, основанного на CryptoNote, который развивался несколько лет теми же руками, которыми был написан оригинальный код технологии.

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


Протокол CryptoNote использует эллиптическую кривую из схемы цифровой подписи с открытым ключом ed25519 [5].

Напомним основные параметры этой кривой и дадим дополнительные определения.

  1. Зафиксировано большое простое число $q = 2^{255}-19$.
    Все операции происходят в целых числах в конечном поле $F_q$ вычетов по модулю $q$.
  2. Задана эллиптическая кривая над полем $F_q$, обозначаемая $E/F_q$:
    $−x^2+y^2= 1 +dx^2y^2$
    где $d = −121665/121666$ (отношение вычисляется в $F_q$ и является целым числом).
    Важным является факт ее симметрии относительно $x$ и $y$.
  3. Над множеством точек кривой геометрически определена операция, для любых двух точек дающая третью: $F(A, B) = C$, условно называемая «сложением», и задан нейтральный элемент, как точка, лежащая в бесконечности (это подробно рассмотрено в [6]). Эта операция не выводит за пределы множества, обладает ассоциативностью, коммутативностью и наличием обратного элемента, благодаря чему все точки кривой вкупе с ней образуют абелеву группу, обозначаемую $E(F_q)$.
    Порядок этой группы (число всех точек): $\# E(F_q)=2^cl$, где $с = 3$ (кофактор) и $l=2^{252}+27742317777372353535851937790883648493$.
  4. Каждая точка кривой задается своими координатами $(x, y)$. Поскольку координаты связаны уравнением кривой, это представление избыточно, и поэтому при реализации криптографических функций для экономии используется только координата $y$, кодируемая как 256-битное число.
    $x$-координата, в соответствии с симметричностью кривой (см. уравнение), может быть только одним из двух вариантов, выбор которого кодируется как старший бит числа, представляющего $y$-координату.
  5. Зафиксирована специальная точка кривой $G = (x, −4/5)$. Точка задается $y$-координатой, из двух возможных вариантов x выбирается положительный.
  6. Сложение (см. п. 3) точки $G$ с самой собой $n$ раз определяет операцию умножения ($*$, опускается в формулах) на целое число, образующую замкнутую мультипликативную группу $\mathbf{G}$, порядок которой меньше, чем $E(F_q)$:
    $\#\mathbf{G} < \#E(F_q)$,
    при этом
    $\#\mathbf{G}=l=2^{252}+27742317777372353535851937790883648493$.
  7. Открытый ключ $X$ — это точка эллиптической кривой, принадлежащая группе $\mathbf{G}$:
    $X \in \mathbf{G} $
  8. Секретный ключ $x$, или скаляр, соответствующий открытому ключу $X$ — это такое целое число, что:
    $X = x*G, x \in [1; l-1]$
    Секретный ключ, также как и открытый (см. выше), кодируется как 256-битное число.
  9. Определена основная хеш-функция $H$ (в коде и других источниках обозначается как cn_fast_hash). Она вычисляет 32-байтный хеш по произвольному набору данных: $H:\{0, 1\}^* \to [0,2^{256}-1]$
  10. Хеш-функция $H_s$ ($s$ означает scalar) по произвольным данным выдает число, являющееся скаляром, т.е. валидным секретным ключом:
    $H_s:\{0,1\}^* \to [1; l-1]$
    $H_s$ может быть реализована тривиально через $H$:
    $H_s(x)= H(x) \mod (l-1) + 1$
  11. Хеш-функция $H_p$ ($p$ означает point — точка кривой) по произвольным данным выдает элемент группы $\mathbf{G}$, то есть, валидный открытый ключ:
    $H_p:\{0,1\}^* \to \mathbf{G}$
    Реализация этой хеш-функции представляет определенную сложность по той причине, что во-первых, не любой набор 256 бит можно декодировать в точку эллиптической кривой (см. п. 4), а во-вторых, не любая точка кривой принадлежит группе $\mathbf{G}$ (см. п. 6).
    Одним из тривиальных способов реализации $H_p$ является последовательное хеширование данных $H(H(...H(x)...))$ до тех пор, пока результат не станет возможным декодировать в точку $X \in \mathbf{G}$.
    В CryptoNote используется более сложный и эффективный подход, реализованный в виде функции ge_fromfe_frombytes_vartime, который подробно рассмотрен в работе [7].
    Определим функцию, детерминированно преобразующую произвольные 256 бит в элемент группы $\mathbf{G}$ как:
    $to\_point : [0,2^{256}-1] \to \mathbf{G}$
    В CryptoNote хеш-функция $H_p$ реализована так:
    $H_p(x) = to\_point( H(x) )$


Вспомним, как происходит отправка средств и расчет баланса в оригинальной версии протокола.

Алиса, отправляя деньги Бобу, формирует выходы своей транзакции следующим образом (рис. 3.1).

  1. У Боба есть пара закрытых ключей $(v, s)$. Он вычисляет свой адрес как пару соответствующих открытых ключей $(V, S)$ и опубликовывает его или отправляет Алисе.
  2. Алиса выбирает случайный секретный ключ транзакции $r$ и вычисляет открытый ключ $R = r G$, который записывает в специальное поле extra транзакции.
  3. Для каждого выхода Алиса вычисляет стелс-адрес (one-time destination key):
    $P_i = H_s(rV, i)G + S$, где $i$ — порядковый номер выхода.
  4. Алиса подписывает и отправляет транзакцию.


Сторонний наблюдатель, анализируя стелс-адреса $P_i$, не может сказать, предназначен ли конкретный выход Бобу, и даже не может определить, предназначены ли разные выходы с ключами $P_i$ и $P_j$ одному получателю.

Чтобы принять деньги, Боб анализирует все транзакции в блокчейне следующим образом (рис. 3.2).

5. Используя свой секретный ключ $v$, Боб вычисляет для каждого выхода $P’_i = H_s(vR, i)G + S$ (где $i$ — порядковый номер выхода, $S$ — открытый spend-ключ Боба).
Если $P’_i = P_i$, то это означает, что он является получателем данного выхода и может его потратить, вычислив соответствующий секретный ключ.Поэтому Боб увеличивает баланс своего кошелька на номинал данного выхода.

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

6. Боб, используя свои секретные ключи $(v, s)$, вычисляет закрытый ключ $x_i = H_s(vR, i) + s$ к стелс-адресу $P_i$, то есть такой, что $P_i = x_i G$.

7. Боб рассчитывает key image: $I = x_i H_p(P_i)$ и записывает его, номинал и ссылку на соответствующий выход во вход своей транзакции для Кэрол.
Следует обратить внимание на то, что, во-первых, вычислить key image может только владелец секретного spend-ключа $s$ (корректность этого будет удостоверена кольцевой подписью), и во-вторых, третья сторона не сможет связать key image $I$ и соответствующий стелс-адрес $P_i$.

8. Боб уменьшает баланс своего кошелька на номинал используемого выхода в п. 6.

9. Боб формирует выходы в транзакции для Кэрол в соответствии с п.п. 2–3. После чего подписывает транзакцию и отправляет.

Если предположить, что Боб утратил всю историю своих операций, но по-прежнему владеет своими секретными ключами $(v, s)$, то он сможет восстановить историю транзакций и рассчитать свой текущий баланс следующим образом (рис. 3.4).

10. Боб сканирует весь блокчейн и анализирует все транзакции на предмет наличия выходов, адресованных ему (см. п. 5).

11. При нахождении такого выхода $P_i$, Боб увеличивает баланс своего кошелька на величину номинала.
Затем, используя свой секретный spend-ключ $s$ вычисляет соответствующий секретный ключ выхода $x_i$ (п. 6) и key image $I$ (п. 7). После чего записывает key image, $P_i$ и другие данные платежа в таблицу.

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

Действуя таким образом, Боб восстановит актуальный баланс своего кошелька.

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

Таким образом, для расчета баланса кошелька Боба необходимо знать оба секретных ключа $(v, s)$.

Если Боб передаст аудитору Дену оба своих секретных ключа $(v, s)$, это будет равносильно передаче самих средств, так как Ден, обладая $s$, сможет их потратить. Поэтому полноценный аудит кошельков в рамках оригинального протокола CryptoNote невозможен.

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

Отметим, что секретный ключ транзакции $r$ Алисе имеет смысл сохранять (что и происходит в некоторых реализациях протокола). Любой, кто знает $r$ для некоторой транзакции, может проверить, относится ли выход $i$ этой транзакции к заданному адресу $(V, S)$, просто повторяя вычисления из п.3:

$P’_i = H_s(rV, i)G + S$

и сравнивая результат с $P_i$.

Этот факт Алиса может, например, использовать, чтобы доказать, что она перевела деньги именно Бобу.

Вычислить целевой адрес $(V, S)$ по выходу, даже зная $r$, нельзя.


В момент своего появления Bytecoin был первой и единственной реализацией протокола CryptoNote, поэтому ему были свойственны все особенности и ограничения, рассмотренные в предыдущем разделе.

7 февраля 2019 года разработчики выпустили ([20]) версию 3.4.0 Amethyst, содержащую ряд улучшений и изменений CryptoNote, которые мы сейчас рассмотрим. Большая часть информации этого раздела была получена путем анализа исходного кода Bytecoin, так как официальной документации не предоставлено.

В рамках тематики этой статьи, наиболее интересным изменением стала возможность для обычных кошельков создавать специальные копии — auditable wallet (AW), обладающие двумя свойствами:

  1. AW не может потратить средства из основного кошелька;
  2. баланс AW всегда совпадает с балансом основного кошелька. Невозможно изменить баланс основного кошелька так, чтобы это не отразилось на балансе AW.


Однако, такой функциональностью обладают только адреса кошельков новых версий, так называемые, amethyst-адреса. С существующими адресами и аккаунтами обеспечивается обратная совместимость, они теперь называются legacy-адреса. Реализация новой функциональности стала возможна только в транзакциях новой версии, поскольку разработчики поменяли формат выходов, поэтому в сети Bytecoin в данный момент циркулируют как транзакции старого формата, так и новые. Транзакции нового формата также поддерживают два типа адресов: amethyst и legacy, поэтому в конечном счете мы имеем три варианта криптографических схем:

  1. tx.version < amethyst, legacy address;
  2. tx.version ≥ amethyst, legacy address;
  3. tx.version ≥ amethyst, amethyst address.


Рассмотрим их более подробно.

4.1. tx.version < amethyst, legacy address


Это оригинальная схема CryptoNote, но с детерминированной генерацией $r$.

Аккаунт кошелька представлен секретным ключом $s$ и хешем $v_s$. Секретный view-ключ $v$ детерминированно генерируется как функция от $v_s$.

Секретный ключ $r$ транзакции теперь выбирается не случайно, а вычисляется при помощи $v_s$:

$r = H_s(h_t, v_s)$, где $h_t = H(tx.inputs, tx.version)$

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

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

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

  1. Алиса сканирует транзакции в блокчейне и ведет учет входящих платежей при помощи секретного view-ключа $v$, как было описано в разделе 3, и увеличивает баланс.
  2. Также для каждого выхода каждой транзакции Алиса перебирает все адреса $(V, S)$ на которые когда-либо осуществлялись переводы и вычисляет:
    $P’_i = H_s(rV, i)G + S$
    Если $P’_i = P_i$, то данный выход является исходящим платежом Алисы на адрес $(V, S)$ и она уменьшает баланс.


Так Алиса рассчитает баланс используя только $v_s$ и $v$.

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

4.2. tx.version ≥ amethyst


Как уже было отмечено выше, начиная с версии 3.4.0 Amethyst в Bytecoin изменился формат транзакций. Если tx.version ≥ amethyst, то выходы транзакции имеют другой формат.

Теперь каждый выход, помимо номинала amount и открытого ключа Pi, содержит также дополнительный открытый ключ Qi (обозначаемый в коде как encrypted_secret) и дополнительный байт, содержащий зашифрованный тип адреса, amethyst или legacy (именуемый в коде encrypted_address_type). Эти структуры схематично показаны на рис. 4.2.

Таким образом, размер каждого выхода увеличился на 33 байта.

Для каждого выхода i тип адреса кодируется и декодируется следующим образом:

encrypted_address_type(i) = (H(oi) & 255) xor address_tag

где:

$o_i = H(h_t, v_s, i)$ (обозначается в коде как output_seed),

address_tag равен 0 для legacy-адресов и 1 для ametyst-адресов.

4.3. tx.version ≥ amethyst, legacy address


Аккаунт кошелька также представлен секретным ключом $s$ и хешем $v_s$, на основе которого детерминированно генерируется секретный view-ключ $v$.

Алиса, отправляя деньги Бобу на его адрес $(V, S)$ формирует выходы своей транзакции следующим образом:

  1. Вычисляет $h_t = H(tx.inputs, tx.version)$, затем для каждого выхода $i$:
  2. $D_i = H_s(h_t, v_s, i)G$ (в коде обозначается как output_shared_secret)
  3. $P_i = S + H_s(D_i, h_t, i)G$
  4. $Q_i = H_s(h_t, v_s, i)V$ (при этом $Q_i = v D_i$, однако view-ключ $v$ получателя неизвестен)
  5. Пара $(P_i, Q_i)$ — открытые ключи выхода $i$.

Чтобы принять деньги, Боб анализирует все транзакции следующим образом.

  6. Для каждой транзакции вычисляет $h_t = H(tx.inputs, tx.version)$, затем для каждого выхода $i$:
  7. $D_i = v^{-1} Q_i$
  8. $S’ = P_i — H_s(D_i, h_t, i) G$
  9. Если $S’$ совпадает с открытым ключом $S$ Боба, то этот выход предназначен ему и он увеличивает баланс своего кошелька на соответствующий номинал.

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

  10. Используя свои секретные ключи $v$ и $s$, вычисляет секретную часть $P_i$:
    $D_i = v^{-1} Q_i$
    $x_i = s + H_s(D_i, h_t, i)$, при этом легко видеть, что $P_i = x_i G$ (см. п. 3).
  11. Боб рассчитывает key image: $I = x_i H_p(P_i)$ и записывает его, номинал и ссылку на соответствующий выход во вход своей транзакции для Кэрол.
  12. Боб уменьшает баланс своего кошелька на номинал используемого выхода.
  13. Боб формирует выходы в транзакции для Кэрол в соответствии с п.п. 1–5. После чего подписывает транзакцию и отправляет.

Особенностью данной схемы, в отличии от CryptoNote, является то, что любой, кому Алиса передаст свой секретный хеш $v_s$, сможет вычислить адрес получателя $(V, S)$ для любой транзакции Алисы:

  14. $D_i = H_s(h_t, v_s, i) G$
  15. $S = P_i — H_s(D_i, h_t, i) G$
  16. $V = H_s(h_t, v_s, i)^{-1} Q_i$

Однако проблемой в данном случае является задача определения, какие транзакции сформировала и отправила Алиса. Без этой информации в п.п. 14–16 для произвольных транзакций будут получатся произвольные бесполезные данные, неотличимые от настоящих адресов $(V, S)$. Некоторую помощь в этом может оказать алгоритм кодирования encrypted_address_type, так как для транзакций Алисы это поле после декодирования будет иметь только допустимые значения $\{0, 1\}$. Но, к сожалению, допустимые значения также могут получится и произвольно, и такой случай нельзя будет отличить.

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

4.4. tx.version ≥ amethyst, amethyst address


Константа H


Для работы этой криптографической схемы требуется введение новой константы — точки $H$, элемента группы $\mathbf{G}$, причем порядок точки $H$ неизвестен. Иными словами, это некоторый зафиксированный открытый ключ, секретная часть которого гарантировано неизвестна и вероятность ее нахождения пренебрежимо мала:

$H = yG$, где $y$ — неизвестное число.

Например, можно задать $H$ так, как предлагается в [8]:

$H = H_p(G) = to\_point( cn\_fast\_hash(G) )$

Разработчики Bytecoin не вычисляют константу, а задают ее численно, без каких-либо указаний на природу ее происхождения:

bytecoin/src/crypto/crypto_helpers.hpp, line 67

constexpr P3 H{ge_p3{{7329926, -15101362, 31411471, 7614783, 27996851, -3197071, -11157635, -6878293, 466949, -7986503},    {5858699, 5096796, 21321203, -7536921, -5553480, -11439507, -5627669, 15045946, 19977121, 5275251},    {1, 0, 0, 0, 0, 0, 0, 0, 0, 0},    {23443568, -5110398, -8776029, -4345135, 6889568, -14710814, 7474843, 3279062, 14550766, -7453428}}};


Однако поиск этой числовой последовательности показал ([9]), что ими используется та же константа, что и в Monero для RingCT, способ вычисления которой и его обоснование рассмотрены в [8].

Поскольку $H$ принадлежит группе $\mathbf{G}$, то можно сказать, что $H$ так же порождает группу $\mathbf{G}$, как и базовая точка $G$.

Это означает, что $ \forall x \in [1,p-1], xH \in \mathbf{G}$

Множественные несвязываемые адреса (unlinkable addresses)


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

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

  1. адреса генерируются детерминированно из первоначального набора секретов;
  2. эти адреса не могут быть связаны между собой, т.е. сторонний наблюдатель не сможет вычислить, что они принадлежат одному аккаунту;
  3. проверка входящих транзакций и учет баланса для $N$ множественных адресов будет вычислительно проще, чем проверка $N$ аккаунтов в обычной схеме.


Аккаунт кошелька представлен секретным ключом $s$ и хешем $v_s$, также, как и в предыдущей схеме. Однако на основе хеша $v_s$ теперь детерминированно генерируется не только секретный view-ключ $v$, но и дополнительный секретный audit-ключ $a$.

Процесс генерации i-го адреса происходит следующим образом (рис. 4.4.2).

  1. Вычисляется $\delta = H_s(A + sH, i)$ и $\Delta = \delta G$
  2. $S = A + sH + Δ$
  3. $V = vS = v(A + sH + Δ) = v(A + sH) + δV$
  4. пара $(V, S) = (v S, S)$ является $i$-ым публичным адресом данного аккаунта.

Заметим, что для расчета достаточно знать следующие величины:
  • $A$
  • $V$
  • $s H$
  • $v (A + s H)$

Величины $s H$ и $v (A + s H)$ предрассчитываются при создании аккаунта и рассматриваются как безопасные в том смысле, что зная их, нельзя вычислить $s$ или $v$.

Сгенерированные адреса хранятся локально в контейнере, оптимизированном для поиска по полю $S$.

Формирование выходов при отправке средств


Алиса, отправля

© Habrahabr.ru