Глава 5

Глубокое погружение в Monero и криптографию

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

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

Сегодня криптография является повсеместно применяемым «закулисным» инструментом обеспечения безопасности, управления, передачи данных и множества других вещей, которые делают нашу повседневную жизнь лучше. Примером может служить изобретение протокола уровня защищённых сокетов, Secure Socket Layer (SSL, который был заменён TSL), основанного на криптографическом подписании контента. Больницы, банки, правительства и бизнес — все защищают информацию, используя криптографию.

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

5.1 Базовые математические принципы

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

5.1.1 Евклидово деление (A / B)

Деление любого числа A на другое число B, записанное как A / B или A÷B, даёт результат, который может быть записан либо как отношение с остатком, либо просто как десятичный разряд.

Generally: A/B = q with remainder r For example: 124 = 3 with remainder 0, which can be written 3.0 in decimal form 134 = 3 with remainder 1, which can be written 3.25 in decimal form 275 = 5 with remainder 2, which can be written 5.4 in decimal form

5.1.2 Простые числа

Простое число является целым (не дробным) числом, которое не делится на какое-либо целое число, кроме 1 и самого целого числа. Например:

20 не является простым числом, поскольку делится на 2, 4, 5 и 10, в результате чего получаются целые числа, например:
20 ÷ 4 = 5
- или -
20 ÷ 10 = 2
7 является простым числом, так как любое целое число, на которые вы станете делить его, не даст в результате не дробного числа, например, 7 ÷ 3 = 2,3333

Примером простых чисел являются 3, 5, 7, 11, 13, 97, 223, 997, 3413, 4421, 17837, 145601, 428567, 1171967, и даже гораздо более длинные числа, такие как 2074722246773485207821695222107608587480996474721117292752992589912196684750549658310084416732550077 или простые числа, разность между которыми равна 2: 2,996,863,034,895  × 2^1,290,000 ± 1, в каждом из которых более 350 000 цифр!

5.1.3 Модулярная арифметика

Модулярная арифметика описывает числа, которые циклически переходят в определённое целое число. Интуитивным примером являются часы в 12-часовым формате. Если вы не ляжете спать на 5 часов, начиная с одиннадцати вечера (11:00), то вы не застанете 16:00 вечера! Вместо этого в полночь время циклически перейдёт в ноль (поэтому спустя 5 часов после одиннадцати вечера настанет четыре утра (4:00) следующего дня).

Допустим, у нас есть два положительных числа: A (делимое) и B (делитель),

тогда A по модулю B = остаток r для A / B.

В контексте часов бодрствование в течение 5 часов после одиннадцати вечера (11:00) можно представить следующим образом:

(11:00 PM + 5 часов) mod 12 = …
= 16:00 mod 12
= 4:00 (AM)

5.1.4 Целочисленное представление

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

Большинству людей вполне знакома «десятичная» система base-10, использующая десять символов:
0,1,2,3,4,5,6,7,8,9.

«Шестнадцатеричная» кодировка добавляет шесть дополнительных символов, образуя набор base-16:
0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f.

Целое число, записанное как 11719682, в системе base-10 может быть выражено как B2D402 в системе base-16. Следует отметить, что больший набор символов требует меньшего количества цифр (меньшей длины строки), чтобы выразить то же самое число.

Компьютеры «думают» в системе base-2, используя только символы 0 и 1. Такая система называется двоичной, и число 11719682 (в системе base-10) было бы представлено в ней как 101100101101010000000010.

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

Вот алфавит base-58:
123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz

Примечание: ноль (0), а также буквы I (верхний регистр i), O (верхний регистр o) и l (нижний регистр L) отсутствуют в алфавите Base58 из-за того, что их можно перепутать друг с другом.

5.1.5 Эллиптические кривые

5.1.5.1 Общая информация

Эллиптические кривые являются набором двумерных (с координатами x, y) точек, удовлетворяющих условия следующего уравнения:

y^2=x^3+ax+b.

Например, при постоянных коэффициентах a = 2 и b = 3 данное уравнение будет выглядеть следующим образом:

y^2=x^3+2x+3,

которому соответствует множество пар точек, таких как:

x = 3 и y = 6
x = 3 и y = -6
x = -1 и y = 0.

5.1.5.2 Эллиптическая кривая Twisted Edwards (Ed25519)

Для выполнения криптографических операций Monero использует определённую эллиптическую кривую под названием Twisted Edwards (Ed25519), являющуюся бирациональным эквивалентом кривой Монтгомери (Curve25519).

Кривая Ed25519 может быть выражена алгебраически как

- x^2 + y² = 1 − (121665/121666) x² y².

Если вернуться к нашему общему уравнению эллиптической кривой, то данная кривая Twisted Edwards является особым случаем, использующим параметры, где:

a = -1 и b = 121665121666.

Недавно стало очевидно, что алгоритм PRNG (алгоритм генерирования псевдослучайных чисел), за которым стоит Национальный институт стандартов и технологий (NIST), имеет ряд недостатков, и что в нём потенциально может быть лазейка. После этого был разработан ряд алгоритмов, соответствующих стандарту NIST4, а кривая Twisted Edwards была выбрана как способ решения многих проблем, которые беспокоили сообщество.

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

Кривая Twisted Edwards (Ed25519) не запатентована, и команда, которая стоит за ней, разработала и адаптировала базовые криптографические алгоритмы с учётом их эффективности. На данный момент эта кривая считается безопасной.

5.1.5.3 Операции на эллиптической кривой

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

Сложение точек на эллиптической кривой происходит иначе, чем обычное сложение, с которым мы сталкиваемся в повседневной арифметике. Чтобы сложить две точки вместе на эллиптической кривой, необходимо найти линию между этими двумя точками, а затем найти точку, в которой кривая будет пересекаться с этой линией. Затем эта точка отражается по оси x для получения окончательной точки.

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

Скалярное умножение использует как точку на кривой, так и целое число. Чтобы умножить точку P на целое число S, точка суммируется сама с собой S раз. Многие криптографические схемы, подобные тем, что используются Monero, используют общую базовую точку на эллиптической кривой в качестве исходной точки для генерирования публичных ключей на основе приватных ключей.

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

5.2 Базовые принципы криптографии

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

Криптографический примитив — это алгоритм, служащий строительным блоком для построения криптографических протоколов. Monero использует самые разнообразные криптографические примитивы в самых различных целях, некоторые из которых были концептуально рассмотрены в Главах 3 и 4. Нарочитый подход Monero к анонимности и доказательству работы (устойчивому к майнингу посредством ASIC) требует более сложных криптографических инструментов, чем те, которые используются многими другими криптовалютами.

5.2.1 Симметричная и асимметричная криптография

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

Симметричное шифрование требует, чтобы участники совместно пользовались какими-то секретными данными. Например, вы шифруете сообщение, используя пароль hunter2, и получатель использует пароль hunter2, чтобы расшифровать его. Для того чтобы осуществлять связь подобным образом, обе стороны должны предварительно согласовать общие (симметричные) секретные данные. Этот практический вопрос ограничивает применимость симметричного шифрования в ряде случаев.

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

Bitcoin использует асимметричное шифрование с использованием двух ключей:

  • приватного ключа для подписания транзакций и расшифровки данных;
  • публичного ключа для верификации подписи и шифрования данных.

Более сложная криптографическая концепция Monero требует использования четырёх ключей:

  • публичного ключа просмотра, используемого для верификации валидности адресов;
  • приватного ключа просмотра, используемого для просмотра таких данных, как баланс, комиссии и суммы транзакций (ключ просмотра нельзя использовать для создания или подписания транзакции);
  • публичного ключа траты, другого публичного ключа, необходимого для верификации транзакций;
  • приватного ключа траты, используемого для подписания транзакций, то есть отправки Monero.

Ваш публичный адрес Monero является прямым представлением пары публичных ключей, в то время как в случае с Bitcoin (и его клонами) используется хеш единственного публичного ключа. Ключи EdDSA (как приватные, так и публичные) имеют длину 256 бит или 64 шестнадцатеричных символа. Не каждое 256-битное целое число является действительной скалярной величиной EdDSA (приватным ключом); оно должно быть меньше, чем «порядок кривой», определяемый уравнением в разделе функции EdDSA.

5.2.2 Хеширование

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

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

Monero использует систему доказательства работы (PoW) CryptoNight, которая применяет специальный алгоритм хеширования CryptoNote на базе хеша Keccak. Алгоритм Keccak победил остальных конкурентов в NIST, чтобы получить обозначение SHA3, и был разработан специалистами, не работающими на NSA. Monero использует хеш-функцию Keccak-256 с 32-байтовым выходом для хеширования как транзакций, так и блоков.

5.2.3 Алгоритм генерирования псевдослучайных чисел Monero

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

Рассмотрим, например, алгоритм генерирования псевдослучайных чисел (PRNG), который просто перетасовывает цифры текущего времени, чтобы создать ключ из 4 цифр. Таким образом, в 10:34 он может выдать ключ 0413, 1403 или 0134… Если вы хотели сохранить ключ в секрете, то вы выбрали самый ужасный метод по нескольким причинам:

  • злоумышленник, которому известно, что вы создали ключ, когда начали работать, примерно в 12:45, будет знать, что в ключе имеются цифры 1 и 2, а это сократит значительно количество возможных вариантов;
  • нет такого значения времени в формате (чч:мм), чтобы в нём было сразу три цифры 9. Фактически вообще нет таких значений времени с любыми тремя цифрами из 6, 7, 8, 9, так как не бывает времени 17:89, 18:78 и так далее. Это попросту невозможно. Это правило исключает множество четырёхзначных кодов, что ещё больше сокращает количество вариантов, которые придётся перебрать злоумышленнику.

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

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

5.3 Создание ключей и адресов Monero

5.3.1 Подбор начального числа

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

Само по себе начальное число представляет собой 256-битное целое число, на основе которого создаются ключи и адреса, например:

112699108505435943726051051450940377552177626778909564691673845134467691053980

Они часто бывают представлены в виде числа base-16 из 64 символов, например:

f9296f587419f1cdede67de160fca14d1069ecaa4c52f012af031eeA09ee039c

(В случае с ключами мнемонического типа, такое представление начального числа само по себе является ключом траты!)

Запись ключа в каком-либо из вышеуказанных стилей довольно сложна, и большинство людей, как правило, делает хотя бы одну ошибку. Преобразование в мнемоническую фразу является следующим шагом, необходимым исключительно для удобства интерпретации и использования человеком. Мнемоническая фраза, по сути, является 256-битным числом, преобразованным в «число» base-1626 (так как в словаре мнемонической фразы насчитывается 1626 слов), состоящее из 24 цифр (24 слов). Такое представление длинной мнемонической фразы гораздо проще прочитать:

lamb hexagon aces acquire twang bluntly argue when unafraid awning academy nail threaten sailor palace selfish cadets click sickness juggled border thumbs remedy ridges border

Когда ваш кошелёк представляет мнемоническую фразу, состоящую из 24 слов, он добавляет ещё одно 25-е слово, которое служит контрольной суммой, позволяющей впоследствии обнаружить опечатки или ошибки. Данный мнемонический метод, используемый Monero, позволяет шифровать в минимальном соотношении 4:3, другими словами, на четыре байта создаётся три слова плюс одно слово в качестве контрольной суммы; на восемь байт создаётся шесть слов плюс одно слово в качестве контрольной суммы и так далее.

Приватный ключ просмотра создаётся путём хеширования мнемонической фразы при помощи Keccak-256, в результате чего получается второе 256-битное целое число, которое затем передаётся функции под названием sc_reduce32, чтобы гарантировать его совместимость с эллиптической кривой. Начальные числа, создаваемые этим способом, всегда будут действительными скалярными величинами, так как сначала они обрабатываются функцией sc_reduce32.

5.3.2 Создание ключей

5.3.2.1 Все ключи

Мнемоническая фраза Monero, о которой говорилось выше, фактически является вашим секретным ключом траты, на основе которого создаются все остальные ключи. Секретный ключ просмотра представляет собой сокращённый хеш вашего секретного ключа траты, преобразованный в действительную скалярную величину для кривой ed25519.

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

5.3.2.2 Кошельки для просмотра

Вы можете выдать доступ исключительно для просмотра вашего счёта Monero, создав кошелёк, используя свой секретный ключ просмотра, но НЕ секретный ключ траты. Такие кошельки для просмотра позволяют увидеть все входящие транзакции, но не потратить ваши Monero или же просмотреть исходящие транзакции.

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

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

Возьмём, к примеру, основной адрес Monero, используемый для пожертвований: 44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A.

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

(f359631075708155cc3d92a32b75a7d02a5dcf27756707b47a2b31b21c389501)

Таким образом, все могут наблюдать за процессом внесения пожертвований.

Так как любой человек, используя ключ просмотра, может увидеть общую сумму, полученную на кошелёк, благотворительный фонд, получивший 100 XMR, не сможет тайно вывести 90 XMR и заявить, что было получено лишь 10. Эта функция особенно важна в тех случаях, когда целью краудфандинга является какая-либо определённая сумма.

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

5.3.3 Создание адресов

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

5.3.3.1 Байт сети

Байт сети используется для того, чтобы дифференцировать различные криптовалюты и сети. В случае с монетами на базе алгоритма CryptoNote, например, соответствующее значение указывается в файле src/CryptoNote_config.h

uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 18;

Основная сеть Monero использует «18» для обозначения первичного (основного) адреса (вот почему основные адреса Monero начинаются с 4, что соответствует системе ASCII). Разработчики Monero используют тестовую сеть и стендовую сеть, у которых есть свои уникальные байты сети:

Название | Значение в коде | Значение ASCII – | – | – Первичный адрес основной сети | 18 | 4 Подадрес основной сети | 42 | 8 Первичный адрес тестовой сети | 53 | 9 Подадрес тестовой сети | 63 | B Первичный адрес стендовой сети | 26 | 5 Подадрес стендовой сети | 36 | 7

5.3.3.2 Объединённые публичные ключи

Публичный ключ траты и публичный ключ просмотра объединяются и прикрепляются к байту сети, в результате чего получается незаконченный адрес (то есть в нём есть всё, кроме контрольной суммы). Несмотря на то, что адрес имеет такой неполный формат, он уже содержит всю информацию ключей: ключи для создания транзакций и метаданные сети, гарантирующие, что транзакция попадёт в правильную сеть.

5.3.3.3 Контрольная сумма

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

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

5.3.3.4 Сведём всё воедино: окончательное оформление адреса

В конечном счёте байт сети, ключи и контрольная сумма объединяются в соответствии со спецификацией Monero:

Индекс | Размер в байтах | Описание – | – | – 0 | 1 | Идентифицирует сеть и тип адреса: 18 для основной сети, 53 для тестовой сети (в base-58, 4 и 9, соответственно) 1 | 32 | Публичный ключ траты 33 | 32 | Публичный ключ просмотра 64 | 4 | Контрольная сумма (хеш, созданный при помощи функции Keccak предыдущих 65 байтов, сжатых до 4 байт)

И, наконец, 69-байтовая строка кодируется в формате base-58 Monero. Это преобразование повышает длину строки до 95 символов, но эту строку можно легко прочитать и записать. Вот и всё! Основной адрес Monero имеет следующий простой состав:

[байт сети + публичный ключ траты + публичный ключ просмотра + контрольная сумма]
А вот пример стандартного адреса:
4BKjy1uVRTPiz4pHyaXXawb82XpzLiowSDd8rEQJGqvN6AD6kWos LQ6VJXW9sghopxXgQSh1RTd54JdvvCRsXiF41xvfeW5

Псевдокод, который приводится ниже, описывает процесс создания публичного адреса. При этом Hs() используется обозначения Keccak хеширования, «||» указывает на объединение строки.

Checksum = Hs(Varint(Prefix) || public spend key || public view key) SerializedString = Base58(Prefix || public spend key || public view key || checksum)

В Главе 7 приводится настоящий код на языке Python, используя который, вы сами сможете создавать ключи и адреса!

5.3.4 Подадреса

Анонимность транзакций Monero достигается при помощи трёх основных конструкций: кольцевых подписей, скрытых (одноразовых) адресов и RingCT. Они позволяют избежать рисков, связанных с привязкой транзакций и анализом данных блокчейна. Тем не менее необходимо учитывать риски связываемости вне блокчейна (другими словами, информация, собранная из других источников, а не за счёт данных самого блокчейна).

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

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

5.3.4.1 Создание подадреса

Вспомним, что у каждого кошелька есть две пары ключей. Приватный ключ просмотра (pV0) и приватный ключ траты (pS0) сохраняются в тайне, в то время как публичный ключ просмотра (PV0) и публичный ключ траты (PS0) кодируются в каждом адресе. Как уже говорилось, публичные ключи генерируются путём умножения приватных ключей на точку-генератор G на эллиптической кривой, то есть (PV0, PS0) = (pV0, pS0)G.

Ваш кошелёк может создать большое количество подадресов, каждый из которых будет иметь отличный индекс i (обычно начинающийся с i=1). Каждый подадрес будет иметь свой собственный набор ключей для каждого индекса с уникальными приватными (pVi, pSi) и публичными (PVi, Psi) ключами.

Формула создания публичного ключа траты для подадреса i будет следующей:

PSi = Hs(pV0||i)G+PS0

Данный процесс начинается с добавления индекса I к приватному ключу просмотра первичного адреса (pV0) и передачи результата посредством функции hash_to_scalar (примечание: на практике исходный клиентский кошелёк также добавляет строку SubAddr к данным в качестве добавки, необходимой для хеширования). Полученная скалярная величина умножается на точку-генератор кривой и добавляется к публичному ключу траты путём добавления точки на эллиптическую кривую.

Этот публичный ключ траты подадреса умножается на первичный приватный ключ траты, чтобы вывести публичный ключ просмотра подадреса:

PVi = pV0*PSi

Публичные ключи подадресов кодируются в публичный адрес в соответствии с тем же правилом, что и первичные адреса:

Subaddress_i = base58(network byte || PSi || PVi || checksum)

Тем не менее байтом основной сети для подадресов будет 0x42, поэтому все они начинаются с цифры 8.

5.3.4.2 Отправка на подадрес

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

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

5.3.4.3 Получение на подадрес

Из-за скрытой природы блокчейна Monero кошельку приходится сканировать каждую транзакцию, чтобы проверить, принадлежит она или нет владельцу. Чтобы подтвердить, что определённый выход X (с публичным ключом транзакции R) был отправлен на первичный адрес, кошелёк проверяет вычисления на основе своего публичного ключа просмотра и публичного ключа траты. Если равенство X==Hs(pV0*R)G+PS0 является правильным, то выход может быть разблокирован и отправлен!

Однако процесс проверки принадлежности выходов к подадресу немного отличается. Вычисление по большей части производится также, за тем исключением того, что член hash_to_scalar вычитается из выхода и сравнивается с публичными ключами траты транзакции. Кошельку известно, что он нашёл выход, принадлежащий ему, если равенство PSi == X - Hs(pV0 * R)G является верным.

5.3.5 Другие методы деривации ключей

Чтобы усилить неопределённость, в настоящее время существует 3 различных метода деривации приватных ключей, используемых Monero (то же самое относится и к Bitcoin). Это методы отличаются несколькими «ключевыми» моментами:

  • Оригинальный (не детерминированный метод): приватный ключ траты и приватный ключ просмотра выбираются независимо и произвольно и формируют аккаунт (счёт). Нет хорошего способа, чтобы зарезервировать не детерминированный счёт, кроме сохранения копии каждого файла. Так как есть лучшие альтернативы, этот громоздкий способ не рекомендуется использовать.
  • Мнемонический (детерминированный метод или Electrum): в этом случае все ключи выводятся на основе одного приватного ключа траты, который считается начальным числом. Приватный ключ просмотра выводится путём хеширования приватного ключа траты при помощи Keccack-256, чтобы получить действительную скалярную величину EdDSA. Создание резервной копии таких счетов не представляет сложности, так как вам просто необходимо записать начальное число (которое обычно выражено мнемонической фразой, записанной в системе base-1626).
  • Метод MyMonero: семейство кошельков MyMonero использует метод, подобный правилу Electrum. Однако мнемоническая фраза состоит из 13, а не из 25 слов. 13 слов преобразуются в 128-битное целое число, которое используется для выведения как ключа траты, так и ключа просмотра. Целое число мнемонической фразы хешируется при помощи Keccak-256 и преобразуется в приватный ключ траты. Этот приватный ключ траты снова хешируется также при помощи Keccak-256 и преобразуется в приватный ключ просмотра.

Возможно, вы отметили критическое отличие в стиле мнемонической фразы MyMonero и Electrum. MyMonero создаёт приватный ключ просмотра, хешируя произвольное целое число, в то время как Electrum хеширует приватный ключ траты. Это означает, что мнемонические фразы, состоящие из 13 и 25 слов, несовместимы: нельзя создать счёт методом Electrum, который будет соответствовать счёту в стиле MyMonero (или наоборот), поскольку пара ключей просмотра всегда будет отличаться.

5.4 Технологии обеспечения анонимности

5.4.1 Скрытые адреса

В Главе 3 было концептуально описано, как одноразовые адреса, также известные как скрытые адреса, позволяют транслировать транзакции в сеть, не раскрывая истинного адреса получателя. В этом разделе мы объясним, как работает криптография, лежащая в основе одноразового публичного ключа.

5.4.1.1 Отправка

Протокол CryptoNote вычисляет получение одноразового адреса по формуле X = Hs(r* PV|i)G + PS. Давайте рассмотрим значение этих символов, а также, как Мария сгенерирует одноразовый адрес, когда будет отправлять деньги Джорджу.

Переменная r является приватным ключом транзакции, представляющим собой 256-битную псевдослучайную скалярную величину. Мария (отправитель) является единственным человеком, который когда-либо узнает этот ключ; даже Джордж (получатель) никогда не узнает произвольного числа, которое кошелёк Марии выбрал в качестве значения r.

Затем Мария умножает публичный ключ просмотра Джорджа, PV, на r, а затем прикрепляет индекс выхода i. Это множество (r* PV|i) затем пропускается через функцию hash_to_scalar, Hs(). Эта функция хеширует свои входы, используя алгоритм Keccak-256, а затем берёт полученное простое число хеш модуля 2^255 + 27742317777372353535851937790883648493.

Член Hs(r* PV|i), вычисленный в предыдущем параграфе, умножается на базовую точку ed25519, G. Наконец, Мария добавляет это множество к публичному ключу траты Джорджа, PS, чтобы получить окончательный выход X, который и является скрытым адресом.

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

5.4.1.2 Получение

Учитывая, как хорошо Мария скрыла Monero, которые она отправляла Джорджу (использовав для этого приватный ключ транзакции, который не известен даже Джорджу), у вас может возникнуть вопрос: как же он найдёт их в блокчейне?!

Как уже было описано в Главе 3, Джорджу необходимо просканировать блокчейн, чтобы найти выходы, принадлежащие ему. Процесс схож с методом, который использовала Мария, чтобы сгенерировать адрес.

Джордж берёт публичный ключ транзакции R из блокчейна и умножает его на свой приватный ключ просмотра, pV. Подобно тому как действовала Мария, Джордж прикрепляет индекс выхода I, а затем применяет функцию hash_to_scalar к (pV*R|i). После этого он умножает результат на G и добавляет свой собственный публичный ключ траты, PS. Если это значение соответствует выходу, то он принадлежит ему.

Другими словами, кошелёк Джорджа сканирует каждую транзакцию в блокчейне, чтобы найти выходы, для которых X = Hs(pV* R|i)G + PS.

5.4.2 Кольцевые конфиденциальные транзакции

Кольцевые конфиденциальные транзакции (RingCT) используются для того, чтобы скрыть сумму Monero, которая передаётся при проведении транзакции. Протокол RingCT был реализован в январе 2017 и стал обязательным для всех транзакций после сентября 2017.

Только те транзакции, которые создают Monero в качестве вознаграждения coinbase, имеют видимые суммы, не замаскированные RingCT. Эта функция предназначена для аудита и позволяет любому участнику сети посчитать и проверить, сколько точно Monero было создано. После такой публичной эмиссии монет транзакции, перед тем как они будут впоследствии использованы, преобразуются в выходы RingCT.

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

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

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

Существует два ключевых аспекта верификации RingCT:

  1. Отправитель путём проверки при помощи доказательства диапазона доказывает, что все выходы содержат положительную сумму. Доказательство диапазона демонстрирует, что замаскированное число может быть сгенерировано как сумма положительных степеней 2, не раскрывая сами порядки. Без доказательств диапазона недобросовестный пользователь, обладающий 5 XMR, мог бы создать транзакцию с парой выходов, содержащую +13 XMR и -8 XMR.
  2. Отправитель также демонстрирует, что количество входов и выходов сбалансировано, что является нетривиальной задачей, учитывая, что кольцевые подписи содержат ложные выходы, не позволяющие верифицирующей стороне узнать истинный источник вводимых средств! Гомоморфные доказательства Педерсена позволяют отправителю доказать, что один из потенциальных входов имеет нулевое расхождение с выходами, не раскрывая суммы, передаваемой в процессе.

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

A = наш выход, никому это не известно

5A + 1A + 4A = 10A ИСТИННО! Верифицировано при неизвестном значении A

6A + 4A + 2A = 14A ЛОЖНО! Не верифицировано, отклонено!

5.4.3 Кольцевые подписи

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

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

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

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

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

Вы собираетесь подписать сообщение транзакции M, используя кольцевую подпись. В настоящее время Monero требует наличия одиннадцати подписантов для создания каждой подписи. Тем не менее давайте рассмотрим упрощённый пример с тремя членами группы. Вам понадобится пара ключей (из публичного и приватного ключа) для выхода, который вы собираетесь потратить, а также выбрать два других выхода (и их публичные ключи), которые послужат в качестве ложных подписантов. Естественно, индексирование членов кольца должно быть произвольным, так как криптографическая анонимность будет разрушена, если действительный подписант всегда будет занимать слот #1. В случае с упрощённым примером с тремя членами кольца, допустим, что ваш кошелёк произвольно поставил истинный источник средств в слот #2.

Вы берёте из блокчейна публичные ключи выходов, которые будете использовать в качестве ложных (P1 и P3), а также у вас есть приватный ключ (p2) и публичный ключ (P2 = p2G) для выхода, который вы тратите. Сначала вы выбираете произвольное число u, которое будет позднее вами опущено. Вы формируете следующее обязательство, начинающееся с индекса, по которому вы взяли ваш ключ:

c3 = Hs(M,uG,uHp(P2))

Чтобы сформировать остальные обязательства, вам также необходимо выбрать произвольные числа s3 и s1, которые вам понадобятся позднее:

c1 = Hs(M,s3G + c3P3 , s3Hp(P3) + c3p2Hp(p2))

Следует отметить, что в данном случае вы включаете несколько порций информации: публичный ключ P3, который берётся вами из блокчейна, ваше произвольное число s_3, предыдущее обязательство c3 и значение p2 Hp (P2), сформированное на основе вашего собственного ключа. Продолжаем:

c2 = Hs(M, s1G + c1P1, s1Hp(P1) + c1p2Hp(P2))

Но это ещё не всё! Чтобы скрыть ваш фактический ключ, вы разумно определяете, что s2 = u − c2 p2. Подпись, которую вы отправляете в блокчейн и демонстрируете всем остальным, содержит несколько множеств (c1 , s1 , s2 , s2 , J), где J = p2Hp(P2) является образом ключа, используемым в каждом обязательстве. Мы переименовываем его в данном случае, чтобы подчеркнуть тот факт, что никому не известны те порции информации, которые были использованы вами для его формирования.

Вот почему это разумно: задавая s2 = u − c2 p2, вы можете провести преобразование, чтобы получилось u = s2 + c2p2. Это означает, что остальные будут видеть первое обязательство c3, созданное вами следующим образом:

c3 = Hs(M, s2G + c2P2, s2Hp(P2) + c2p2Hp(P2))

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

Отметьте, что образ ключа J = p2Hp(P2) был уникально вычислен на основе пары ключей действительного выхода без каких-либо случайных чисел или публичных ключей ложных выходов. Таким образом, любые мошеннические попытки повторно потратить выход приведут лишь к созданию идентичного образа ключа. А так как сеть отслеживает, какие образы ключей уже были потрачены, любые попытки повторно потратить выходы будут легко обнаружены и отклонены.

Следует отметить, что вышеприведённый пример «обратной» LSAG-подписи включён в образовательных целях, и его не следует использовать в качестве образца для реальной реализации.

5.4.4 Другие источники информации

Если вы хотите узнать ещё больше о вычислениях, которые стоят за этими технологиями, прочитайте «Monero с нуля», крайне технический и математический документ в формате .pdf, создание которого было профинансировано сообществом.

5.5 Блокчейн Monero

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

5.5.1 База данных в памяти (LMDB)

Для сохранения своего блокчейна Monero использует базу данных в памяти LMDB (Lightning Memory Mapped Database). LMDB представляет сбой программную библиотеку, обеспечивающую производительное управление встроенной базой данных транзакций в форме хранилища значений ключей. Это означает, что она очень эффективна и гарантирует простоту поиска.

LMDB написана на языке C++, имеет привязки API для нескольких языков программирования и была разработана Symas Corporation. Вот несколько характерных особенностей LMDB:

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

5.5.2 Структура блока

Стандарты CryptoNote определяют спецификации хранения и распределения данных в блоках, а также в блокчейне. Структура блока включает в себя три основных компонента:

  • заголовок блока;
  • базовую транзакцию;
  • список идентификаторов транзакций (хешей транзакций, добытых в блоке).

5.5.2.1 Заголовок блока

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

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

Поле | Тип | Содержание – | – | – major_version | varint | Основная версия заголовка блока minor_version | varint | Младшая версия заголовка блока timestamp | varint | Время создания блока (временная метка UNIX) prev_id | хеш | Идентификатор предыдущего блока nonce | 4 байта | Любое значение, используемое алгоритмом консенсуса сети

5.5.2.2 Базовая транзакция

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

5.5.2.3 Вычисление идентификатора блока

Поле | Тип | Содержание – | – | – version | varint | Версия формата транзакции unlock_time | varint | Временная метка UNIX input_num | varint | Количество входов. В случае с базовыми транзакциями всегда 1 input_type | байт | В случае с базовыми транзакциями всегда 0xff height | varint | Высота блока, который содержит транзакция output_num | varint | Количество выходов outputs | массив | Количество выходов

За базовой транзакцией следует список идентификаторов транзакции. Эти идентификаторы вычисляются при помощи Keccak хэша тела транзакции. Список начинается с количества идентификаторов, за которым следуют сами идентификаторы (если блок не пуст).

5.5.2.4 Вычисление идентификатора блока

Идентификатор блока вычисляется путём хеширования следующих данных при помощи алгоритма Keccak-256:

  • размер block_header;
  • block_header
  • корневой хеш Меркла;
  • количество транзакций (varint).

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

5.5.3 Экономические принципы майнинга

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

5.5.3.1 Вознаграждение coinbase за майнинг

Как уже говорилось в Главе 4, все Monero появляются как вознаграждение, выплачиваемое майнерам за успешное завершение блоков. Размер этой выплаты coinbase зависит от текущей денежной массы (A) и начального количества атомарных единиц (S = 264 — 1). Атомная единица является самой малой частью Monero, существующей в сети на данный момент (1x10-12 XMR):

Базовое вознаграждение = 2 * ((S - A) * 2-20 * 10-12)

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

5.5.3.2 Динамический размер блока

У Monero динамический размер блока, позволяющий непрерывно корректировать рост сети, в отличие от множества других криптовалют, использующих статичный (фиксированный) размер блока. Например, начальный размер блока Bitcoin, составляющий 1 MB, вызвал проблемы с масштабированием, так как было ограничено количество транзакций, которое можно было бы включить в блок (а впоследствии и общий объём транзакций, который можно было бы включить в сеть). В 2017 году это ограничение вызвало временное, но серьёзное повышение размера комиссий, а также задержки с обработкой транзакций. Были предложены различные варианты решения, которые привели к долгим дебатам.

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

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

Если вычисленный блок имеет размер (B), который больше среднего размера последних 100 блоков (MN), то часть базового вознаграждения удерживается согласно формуле:

Штраф = Базовое вознаграждение * ((B/MN) - 1)2

Майнеры получают полное вознаграждение за блок любого размера до 300 kB; если размер блока больше, включается штрафная функция. Максимальный размер блока составляет 2* MN. После этого значения вознаграждение coinbase полностью удерживается.

5.5.3.3 Комиссии

Если объём транзакций низок, а размер блоков мал, майнеры получают полное вознаграждение coinbase, а размер комиссий минимален.

Тем не менее представьте себе иной сценарий: что произойдёт, если средний размер последних 100 блоков больше, чем не облагаемый штрафом размер блока, составляющий 300 kB? В этом случае вступает в игру алгоритм динамических комиссий!

Комиссии вычисляются в зависимости от «веса» транзакций, выраженного в kB. Чем больше («тяжелее») транзакция, тем выше будет комиссия. Динамическое вычисление комиссий — сложный процесс, учитывая несколько факторов экосистемы Monero и приоритет транзакций (отправитель может ускорить работу майнеров, заставив их провести срочную транзакцию путём увеличения размера комиссии). Комиссии обязательно должны быть конкурентными в следующем блоке, и вычисляться по формуле:

Комиссия на kB = (R/R0) * (M0/M) * F0 * (60/300) * 4
  • R является базовым вознаграждением;
  • R0 является исходным базовым вознаграждением (10 XMR);
  • M является предельным значением размера блока;
  • M0 является минимальным предельным значением размера блока (300 kB);
  • F0 является 0.002 XMR;
  • 60 / 300 является корректировочным коэффициентом счёта для повышения не облагаемого штрафом предельного размера блока (в 2017 оду был увеличен с 60 kB до 300 kB);
  • 4 является корректировочным коэффициентом счёта для множителя комиссии, используемого по умолчанию (при минимальном уровне комиссии используется множитель x1, а в случае с транзакциями с обычным приоритетом — x4).

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

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

Алгоритм динамического размера комиссий предназначен для случаев, когда средний размер блока последовательно вырастает выше значения 300 kB. Несмотря на то, что система разработана с тем расчётом, чтобы учитывать рост цены, она ещё недостаточно идеально коррелирует с ценой, а, следовательно, пока что является неидеальным инструментом.

5.5.4 Bulletproofs

Доказательства Bulletproofs являются новым средством, позволяющим значительно снизить размер транзакций, что, в свою очередь, ведёт к снижению общего размера комиссий за проведение транзакций! Размер транзакций Monero, как правило, был довольно большим (обычно более 12 kB), поэтому реализация Bulletproofs ожидалась с нетерпением.

Механизмы обеспечения анонимности Monero проводят несколько сложных «тестов» при валидации транзакций, чтобы не допустить нарушения правил или проведения спам-атаки. Сюда входят верификация замаскированных сумм, проверка комиссий, подтверждение отсутствия двойной траты.

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

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

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

Bulletproofs используют некоторые математические хитрости, позволяющие построить доказательство диапазона при помощи более эффективного механизма. Размер одного доказательства диапазона при этом сокращается до 2 kB!

До реализации Bulletproofs транзакции с множеством выходов требовали множество отдельных доказательств диапазона. Вследствие этого размер транзакции увеличивался линейно с ростом количества выходов (например, 1 выход = 7 kB, 2 выхода = 14 kB). При использовании Bulletproofs размер изменяется логарифмически с ростом количества выходов (например, 1 выход = 2 kB, 2 выхода = 2.5 kB).

За счёт снижения размера каждого доказательства диапазона, а также их более эффективного комбинирования, Bulletproofs позволили значительно снизить размер транзакций, а следовательно, и размер комиссий. Bulletproofs были реализованы в рамках обновления сети Monero до версии v0.13.0, которое состоялось в октябре 2018 года. Пока что они стали опцией, которая станет обязательной при последующем обновлении.