Рейтинг:0

Конкатенация в деревьях Меркла

флаг in

Рассмотрим простое дерево Меркла с листьями. Алиса +100 и боб +50. Используя хеш-алгоритм SHA256, дайджест соответствующих строк выглядит следующим образом:

# Алиса +100
dc2cac4a8aaeccc0199eeb77df68b22eaa6e319d3f2b425d078dbd73419e28ac

# боб +50
7e15e5bc1b84f458db7ced4df762ba70204f19e3a613738756f9b00653f0aee1

Будучи хэш-функцией, SHA-256 является детерминированным, поэтому не имеет значения, на каком языке программирования мы его реализуем. Для полноты картины это можно сделать с помощью крипто-js библиотека:

const hash256 = (строка) => {
  константное значение = 
  require('crypto').createHash('sha256').update(string).digest('hex');
  возвращаемое значение;
}

# применять
hash256('Алиса +100')
# Результаты:
dc2cac4a8aaeccc0199eeb77df68b22eaa6e319d3f2b425d078dbd73419e28ac

Когда человек обращается к Реализация дерева Меркла, можно увидеть следующее описание:

Хеш-дерево — это дерево хэшей, листьями которого являются хэши блоков данных, например, в файле или наборе файлов. Узлы, расположенные дальше по дереву, являются хэшами соответствующих дочерних узлов. Например, на приведенном выше рисунке хеш 0 является результатом хеширования конкатенации хэша 0-0 и хэша 0-1. То есть хэш 0 = хеш (хеш (0-0) + хеш (0-1)), где + обозначает конкатенацию.

введите описание изображения здесь

Я видел абстракции библиотеки более высокого уровня, которые реализуют эту конкатенацию в случае Буфер.concat(), но я хотел бы знать, как именно это реализовать с чисто математической точки зрения.

Можно предположить (ошибочно):

alice_hash = hash256('Алиса +100')
bob_hash = hash256 ("боб +50")
# неправильный
hash256 (alice_hash + bob_hash)
# тоже неправильно: добавление префикса 0x
хеш256(
  '0xdc2cac4a8aaeccc0199eeb77df68b22eaa6e319d3f2b425d078dbd73419e28ac'
  + 
  '0x7e15e5bc1b84f458db7ced4df762ba70204f19e3a613738756f9b00653f0aee1' 
)

Итак, без всяких абстракций, как бы объединить два хэша получить результирующий родительский узел?

Для тех, кто пытается помочь, правильное значение hash(hash(alice) + hash(bob)) должно быть edf9a9a0e56b58fc9caccb97d85c628d5b9dc50cb94dfc41e83026d37704400f. Пробовал добавлять/удалять 0x префикс, добавляя между ними один пробел, и ни одна из этих попыток не увенчалась успехом.Я также читал статьи, которые я мог получить, но так и не продвинулся дальше, чем «объединить их, чтобы получить значение для родительского узла» с очень небольшим количеством ссылок на реализацию.

kelalaka avatar
флаг in
И ответ, и вы, и ваш источник забыли правильно использовать дерево Меркла 0s 1s. [См. в этом ответе] (https://crypto.stackexchange.com/a/71313/18298)
Morrolan avatar
флаг ng
Чтобы уточнить, что @kelalaka имел в виду, правильные реализации деревьев Меркла обычно добавляют идентификатор *где в дереве* хешированный элемент находился к хешируемым данным. Это помогает предотвратить определенные типы атак. Есть разные способы сделать это. Один виден в связанном ответе, другой в [RFC 6962] (https://www.rfc-editor.org/rfc/rfc6962.html#section-2.1), где они просто различают листовые и нелистовые узлы.
onlyphantom avatar
флаг in
Я понимаю и искренне ценю отзывы и ссылки здесь.Я пропустил другие детали, чтобы сосредоточиться на части «конкатенации». Но после вашего ответа @Morrolan я смог это понять и правильно реализовать на питоне. Вывод заключался в том, чтобы рассматривать шестнадцатеричную строку просто как представление. Вместо этого выполните + в двоичной строке. Спасибо за ответ!
Рейтинг:1
флаг ng

Проблема возникает из-за того, что шестнадцатеричное строковое представление («hexdigest») хэш-значения смешивается с его фактическим двоичным значением.

Напомним сначала, что хэш-функция принимает в качестве входных данных строку битов произвольной длины (для практических целей) и выводит строку битов фиксированной длины. То есть действует на бинарный ценности.

Таким образом, фактическое хеш-значение входной строки (в кодировке ASCII) Алиса +100 представляет собой последовательность из 32 байтов. dc2cac4a8aaeccc0199eeb77df68b22eaa6e319d3f2b425d078dbd73419e28ac представляет собой последовательность байтов, представленную как «hexdigest», где каждые два шестнадцатеричных символа кодируют один байт.

Для операции конкатенации вы должны конкатенировать последовательности байтов, а не их шестнадцатеричные дайджесты.

Один пример в Руби:

требуется «дайджест»

m1 = 'Алиса +100'
м2 = 'боб +50'

d1 = Дайджест::SHA256.new
d2 = Дайджест::SHA256.new

д1 << м1
д2 << м2

помещает "Алиса hexdigest: #{d1.hexdigest}"
помещает "Боб hexdigest: #{d2.hexdigest}"

d3 = Дайджест::SHA256.new
d3 << d1.дайджест
d3 << d2.дайджест                                                                                                                                                

ставит "Конкатенация hexdigest: #{d3.hexdigest}"

Дает при выполнении:

Шестнадцатеричный дайджест Алисы: dc2cac4a8aaeccc0199eeb77df68b22eaa6e319d3f2b425d078dbd73419e28ac
Шестнадцатеричный дайджест Боба: 7e15e5bc1b84f458db7ced4df762ba70204f19e3a613738756f9b00653f0aee1
Шестнадцатеричный дайджест конкатенации: edf9a9a0e56b58fc9caccb97d85c628d5b9dc50cb94dfc41e83026d37704400f

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

Ответить или комментировать

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