Loading AI tools
полное двоичное дерево, в листовые вершины которого помещены хеши от блоков данных, а внутренние вершины содержат хеши от сложения значени Из Википедии, свободной энциклопедии
Дерево хешей (дерево Меркла) — полное двоичное дерево, в листовые вершины которого помещены хеши от блоков данных, а внутренние вершины содержат хеши от сложения значений в дочерних вершинах. Корневой узел дерева содержит хеш от всего набора данных, то есть хеш-дерево является однонаправленной хеш-функцией. Применяется для эффективного хранения транзакций в блокчейне криптовалют (например, в Bitcoin, Ethereum). Оно позволяет получить «отпечаток» всех транзакций в блоке, а также эффективно верифицировать транзакции[1]. Названо по имени Ральфа Меркла, предложившего в 1979 году соответствующую технику хеширования криптографических функций.
Заполнение значений в узлах дерева идет снизу вверх. Сперва к каждому блоку данных применяется хеширование, и так далее. Полученные значения записываются в листья дерева. Блоки, находящиеся уровнем выше, заполняются как хеши от суммы своих детей, , где обычно означает конкатенацию. Эта операция повторяется, пока не будет получено верхнее значение — или merkle_root
[1].
В биткойне в качестве хеш-функции используется двойное SHA-256, то есть [1]. Впрочем, хеш-функция может быть любой, например Tiger Tree Hash (TTH), используемый в файлообменных p2p-сетях, является деревом Меркла с хеш-функцией Tiger[2].
Если количество блоков на каком-то уровне дерева оказывается нечетным, то один блок дублируется[1] или переносится без изменений на следующий уровень, как это происходит при вычислении Tiger Tree Hash[2].
Хеш-деревья имеют преимущество перед хеш-цепочками или хеш-функциями. При использовании хеш-деревьев гораздо менее затратным является доказательство принадлежности определённого блока данных к множеству. Поскольку различными блоками часто являются независимые данные, такие как транзакции или части файлов, то нас интересует возможность проверить только один блок, не пересчитывая хеши для остальных узлов дерева. Пусть интересующий нас блок — это (см. рис.). Тогда доказательством его существования и валидности будут корневой хеш, а также верхние хеши других веток ( и )[1][3]. В данном случае проверка не пройдена, если .
В общем случае можно записать
,
а проверку осуществить как , где
.
Набор блоков называется аутентификационный путь или путь Меркла[1].
Видно, что проверку выше можно выполнить за действий, где — это высота дерева или длина аутентификационного пути, а — это количество блоков данных. Такая же проверка в случае хеш-цепочки имела бы сложность [1][4].
Таблица ниже демонстрирует, что даже при значительном количестве транзакций в блоке о сложности вычислений можно не беспокоиться[1].
Количество транзакций | Приблизительный размер блока | Размер пути (в хешах) | Размер пути (в байтах) |
---|---|---|---|
16 транзакций | 4 килобайта | 4 хеша | 128 байт |
512 транзакций | 128 килобайт | 9 хэшей | 288 байт |
2048 транзакций | 512 килобайт | 11 хэшей | 352 байт |
65535 транзакций | 16 мегабайт | 16 хэшей | 512 байт |
Блок биткойна хранит только значение merkle_root
своих транзакций. Это позволяет получить определённые преимущества и снизить нагрузку на сеть.
После накопления достаточного числа блоков можно удалять старые транзакции для экономии места. При этом сам блок остается неизменным, так как в нём хранится только merkle_root
. Блок без транзакций занимает 80 Б, или 4,2 МБ в год (при генерации блока каждые 10 минут)[5].
Становится возможной упрощенная проверка оплаты (англ. Simplified payment verification). SPV-узел загружает не весь блок, а только заголовок блока. Для интересующей его транзакции он запрашивает также её аутентификационный путь. Таким образом он загружает всего несколько килобайт, тогда как полный размер блока может быть больше 10 мегабайт (см. таблицу)[1]. Использование этого метода, однако, требует, чтобы пользователь доверял узлу сети, у которого будет запрашивать заголовки блоков. Один из способов избежать атаки, то есть подмены узла недобросовестной стороной, — рассылать оповещения по всей сети при обнаружении ошибки в блоке, вынуждая пользователя загружать блок целиком[5].
На упрощенной проверке оплаты основана работа так называемых «тонких» биткойн-клиентов[6][7].
Дерево Меркла имеет также и недостатки, проявляющиеся при растущем количестве листьев. Как было показано ранее, для вычисления подписи произвольного блока нужно знать все значения из множества . Это не вызывает проблем, если есть возможность хранить все внутренние вершины дерева в памяти, однако для больших деревьев (количество листьев может увеличиваться до ) это не подходит. Можно также каждый раз вычислять внутренние блоки заново, но это значительно понизит производительность такой системы. Поэтому возникает проблема эффективного обхода дерева и генерации подписей (англ. Merkle tree traversal problem)[4]. На сегодняшний день существуют решения, использующие времени и памяти, где — это количество листьев. Было также доказано, что не существует алгоритма обхода, который бы был одновременно лучше, чем и по времени, и по памяти[8].