Может есть такая схема алгоритма этой Хеш-функии? Понятно что есть компонент, но мне нужна именно схема для полного понимания работы.
Этот топик читают: Andrej77rv, Гость
Ответов: 125
Рейтинг: 1
|
|||
карма: 1 |
|
Ответов: 4665
Рейтинг: 767
|
|||
А описание в Википедии или на других ресурсах не подходит?
|
|||
карма: 26 |
|
Ответов: 125
Рейтинг: 1
|
|||
Netspirit писал(а): А описание в Википедии или на других ресурсах не подходит?Нет. Со схемой лучше понять можно. |
|||
карма: 1 |
|
Ответов: 125
Рейтинг: 1
|
|||
карма: 1 |
|
Ответов: 524
Рейтинг: 167
|
|||
Andrej77rv писал(а): Вообще не особо понятноЗадал вопрос ИИ - ответ. Может чего прояснится... ![]() Отличный вопрос! Объясню алгоритм SHA-256 максимально просто, как будто мы готовим сложное блюдо по рецепту. Не пугайтесь терминов, мы их сразу будем "переводить". SHA-256 — это алгоритм, который превращает любые данные (текст, файл) в уникальную "отпечаток" длиной 256 бит (64 символа). Это как гигантский мясорубка: вы закидываете туда что угодно (от огурца до целого торта), а на выходе получается одинаковый по длине фарш, по которому нельзя понять, что было на входе, но он уникален для каждого исходного продукта. Главные Свойства (Почему он так важен): Детерминированность: Один и тот же вход всегда даёт один и тот же хеш. Быстрый вычисление: Хеш от любого сообщения вычисляется очень быстро. Необратимость: По хешу практически невозможно восстановить исходные данные. (Нельзя из фарша собрать обратно огурец). Уникальность: Малейшее изменение во входных данных (даже один символ или бит) полностью меняет хеш до неузнаваемости. Это называется "эффект лавины". Устойчивость к коллизиям: Крайне маловероятно, что два разных сообщения дадут одинаковый хеш. "Рецепт" приготовления SHA-256 Представьте, что мы готовим блюдо. Наши исходные данные — это ингредиенты. Шаг 0: Подготовка ингредиентов (Предобработка) Допустим, мы хотим захэшировать слово "Привет". Переводим в байты: Сначала преобразуем наше сообщение в последовательность битов (нулей и единиц). П -> р -> и -> в -> е -> т становится какой-то длинной строкой из 0 и 1. Добавляем единицу: В конец нашей битовой последовательности добавляем 1. Зачем? Это как пометить начало нашего настоящего сообщения внутри большого блока. Добавляем нули: Теперь нам нужно сделать общую длину сообщения такой, чтобы оно было кратно 512 битам, но с небольшим хвостиком. Мы добавляем столько нулей, чтобы: [длина исходного сообщения] + 1 + [количество добавленных нулей] + 64 = 512 * N Зачем? Наш алгоритм "перемалывает" данные блоками по 512 бит. Мы должны подготовить данные так, чтобы они идеально поместились в эти блоки. Добавляем длину сообщения: В оставшиеся 64 бита мы записываем длину исходного сообщения в битах. Зачем? Это добавляет дополнительную защиту от certain types of attacks. Это как написать на коробке настоящий вес продукта до того, как его перемололи. В итоге у нас получилось одно или несколько "корыт" данных по 512 бит в каждом. Теперь будем перемалывать каждое корыто по очереди. Шаг 1: Подготовка специй (Инициализация констант) У нас есть 8 "начальных специй" — это константы, которые являются дробными частями от кубических корней первых 64 простых чисел. Они называются h0 до h7. Просто запомните, что это набор из 8 случайно-выглядящих 32-битных чисел, заданных создателями алгоритма. Также у нас есть 64 "дополнительные специи" — константы K[0..63]. Это дробные части от кубических корней первых 64 простых чисел. Эти числа не случайны, их выбор доказывает, что в алгоритме нет "задних дверей". Шаг 2: Приготовление одного блока (512 бит) Возьмем наши первые 512 бит подготовленных данных. Разделим на 16 "порций" по 32 бита: Назовем их M[0] до M[15]. Пока это просто наши нарезанные данные. Расширяем "меню" до 64 порций: Мы берем наши 16 порций и по специальным формулам "выдавливаем" из них еще 48, чтобы получилось 64 порции (W[0] до W[63]). Формулы используют не только сами числа, но и их побитовые сдвиги и вращения. Это нужно для того, чтобы каждый бит исходных данных повлиял на множество вычислений далее. Формулы: Для i от 0 до 15: W[i] = M[i] (просто копируем) Для i от 16 до 63: W[i] = σ1(W[i-2]) + W[i-7] + σ0(W[i-15]) + W[i-16] (Не пугайтесь! σ0 и σ1 — это просто функции, которые перемешивают биты внутри числа с помощью вращений и сдвигов. Это как очень интенсивно перемешать специи). Инициализация рабочей переменной: Мы берем наши текущие значения "главных специй" h0-h7 и копируем их в рабочие переменные a, b, c, d, e, f, g, h. Главный цикл перемешивания (64 раунда): Это самый важный этап. Мы делаем 64 раза одно и то же, но с разными "специями" (K[i]) и разными "порциями" данных (W[i]). Каждый раунд немного меняет значения a-h. Вот что происходит в одном раунде (упрощенно): Мы смотрим на текущие значения a-h. По сложной формуле считаем два временных числа: Σ1 = (e вращать вправо на 6 бит) XOR (e вращать вправо на 11 бит) XOR (e вращать вправо на 25 бит) Ch = (e AND f) XOR ((NOT e) AND g) ("выбрать" бит: если e=1, то выбираем f, если e=0, то выбираем g) Temp1 = h + Σ1 + Ch + K[i] + W[i] Считаем еще два числа: Σ0 = (a вращать вправо на 2 бита) XOR (a вращать вправо на 13 бит) XOR (a вращать вправо на 22 бит) Maj = (a AND b) XOR (a AND c) XOR (b AND c) ("мажоритарный" бит: значение, которое чаще встречается на этой позиции у a, b, c) Temp2 = Σ0 + Maj Сдвигаем рабочие переменные: h = g g = f f = e e = d + Temp1 d = c c = b b = a a = Temp1 + Temp2 Что это было? Это один раунд сжатия. Каждый бит данных W[i] и каждая константа K[i] интенсивно перемешиваются со всеми рабочими переменными. Сдвиги (a->b, b->c и т.д.) обеспечивают то, что влияние одного бита распространяется по всем переменным в последующих раундах. Добавляем результат к "главным специям": После 64 раундов мы берем наши изменившиеся рабочие переменные a-h и прибавляем их к изначальным значениям h0-h7. h0 = h0 + a h1 = h1 + b ... h7 = h7 + h Шаг 3: Подаем на стол (Формирование результата) Мы повторили Шаг 2 для всех наших 512-битных блоков. Каждый следующий блок обрабатывается с новыми значениями h0-h7, полученными после предыдущего блока. Когда все блоки обработаны, мы просто берем итоговые значения h0, h1, h2, h3, h4, h5, h6, h7, записываем их в одну длинную строку в шестнадцатеричном формате (от 0 до 9 и A до F) — и это и есть наш финальный хеш! Для "Привет" хеш будет: a4d55e3c6d6f6e31e4e2f6a7d55c39c7a4b9c6d3e7f2a1b8c5d4e3f2a1b8c5d (Это пример, не настоящий хеш, просто чтобы показать длину). Итог простыми словами: Нарезаем и дополняем данные до удобного размера. Берем начальные значения (специи), заданные создателями. Перемалываем каждый блок данных в 64 раунда, интенсивно перемешивая их с начальными значениями с помощью сдвигов, вращений и логических операций. Смешиваем результат от каждого блока с результатом следующего. Склеиваем финальные 8 значений в одну строку — это и есть хэш. Это гениальный и очень эффективный механизм, который обеспечивает безопасность всего современного интернета, от паролей до блокчейна. |
|||
карма: 4 |
|
Ответов: 125
Рейтинг: 1
|
|||
tig-rrr писал(а): Andrej77rv писал(а):
Вообще не особо понятно Задал вопрос ИИ - ответ. Может чего прояснится... Спасибо. В начале всё понятно. Не понятно в конце. Т.е. мы берём исходное число и суммируем по модулю 2 с тем,что после преобразований и битовых сдвигов? Или нет? --- Добавлено в 2025-08-22 19:10:16 Полную схему нигде не могу найти. Везде "обрезки". Редактировалось 1 раз(а), последний 2025-08-22 19:10:16 |
|||
карма: 1 |
|
Ответов: 524
Рейтинг: 167
|
|||
Andrej77rv писал(а): Полную схему нигде не могу найтиможет код алгоритма прояснит ситуацию на Payton ![]() import struct import binascii def sha256(message): # Шаг 0: Предобработка - подготовка сообщения # Преобразуем строку в байты если это еще не сделано if isinstance(message, str): message = message.encode('utf-8') # Инициализация констант (начальные значения h0-h7) # Эти значения получаются из дробных частей квадратных корней первых 8 простых чисел h0 = 0x6a09e667 h1 = 0xbb67ae85 h2 = 0x3c6ef372 h3 = 0xa54ff53a h4 = 0x510e527f h5 = 0x9b05688c h6 = 0x1f83d9ab h7 = 0x5be0cd19 # Константы K (дробные части кубических корней первых 64 простых чисел) K = [ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 ] # Вспомогательные функции def right_rotate(x, n): """Циклический сдвиг вправо на n бит""" return (x >> n) | (x << (32 - n)) & 0xFFFFFFFF # Функции, используемые в алгоритме def Ch(x, y, z): """Функция выбора: если x то y, иначе z""" return (x & y) ^ (~x & z) def Maj(x, y, z): """Мажоритарная функция: возвращает бит, который чаще встречается""" return (x & y) ^ (x & z) ^ (y & z) def Sigma0(x): """Σ0 функция - перемешивание битов""" return right_rotate(x, 2) ^ right_rotate(x, 13) ^ right_rotate(x, 22) def Sigma1(x): """Σ1 функция - перемешивание битов""" return right_rotate(x, 6) ^ right_rotate(x, 11) ^ right_rotate(x, 25) def sigma0(x): """σ0 функция - используется при расширении сообщения""" return right_rotate(x, 7) ^ right_rotate(x, 18) ^ (x >> 3) def sigma1(x): """σ1 функция - используется при расширении сообщения""" return right_rotate(x, 17) ^ right_rotate(x, 19) ^ (x >> 10) # Предобработка сообщения length = len(message) * 8 # Длина в битах message += b'\x80' # Добавляем бит '1' (0x80 = 10000000 в двоичной) # Добавляем нули пока длина не станет ≡ 448 (mod 512) while (len(message) * 8) % 512 != 448: message += b'\x00' # Добавляем длину исходного сообщения как 64-битное big-endian число message += struct.pack('>Q', length) # Разбиваем сообщение на блоки по 512 бит (64 байта) blocks = [] for i in range(0, len(message), 64): blocks.append(message[i:i+64]) # Обработка каждого блока for block in blocks: # Создаем расписание сообщения W[0..63] W = list(struct.unpack('>16L', block)) # Первые 16 слов # Расширяем до 64 слов for i in range(16, 64): s0 = sigma0(W[i-15]) s1 = sigma1(W[i-2]) W.append((W[i-16] + s0 + W[i-7] + s1) & 0xFFFFFFFF) # Инициализируем рабочие переменные текущими значениями хеша a, b, c, d, e, f, g, h = h0, h1, h2, h3, h4, h5, h6, h7 # Главный цикл сжатия (64 раунда) for i in range(64): # Вычисляем временные переменные T1 = (h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]) & 0xFFFFFFFF T2 = (Sigma0(a) + Maj(a, b, c)) & 0xFFFFFFFF # Обновляем рабочие переменные h = g g = f f = e e = (d + T1) & 0xFFFFFFFF d = c c = b b = a a = (T1 + T2) & 0xFFFFFFFF # Добавляем результат этого блока к общему хешу h0 = (h0 + a) & 0xFFFFFFFF h1 = (h1 + b) & 0xFFFFFFFF h2 = (h2 + c) & 0xFFFFFFFF h3 = (h3 + d) & 0xFFFFFFFF h4 = (h4 + e) & 0xFFFFFFFF h5 = (h5 + f) & 0xFFFFFFFF h6 = (h6 + g) & 0xFFFFFFFF h7 = (h7 + h) & 0xFFFFFFFF # Собираем финальный хеш из h0-h7 digest = (h0 << 224) | (h1 << 192) | (h2 << 160) | (h3 << 128) | \ (h4 << 96) | (h5 << 64) | (h6 << 32) | h7 # Преобразуем в строку из 64 hex-символов return '{:064x}'.format(digest) # Тестирование функции if __name__ == "__main__": test_cases = [ "", "Hello, World!", "The quick brown fox jumps over the lazy dog", "Python", "SHA-256" ] print("Тестирование SHA-256:") print("-" * 80) for test in test_cases: result = sha256(test) print(f"'{test}'") print(f"SHA-256: {result}") print(f"Длина: {len(result)} символов") print() # Сравнение со встроенной функцией для проверки test_msg = "Hello" our_hash = sha256(test_msg) builtin_hash = binascii.hexlify(__import__('hashlib').sha256(test_msg.encode()).digest()).decode() print("Проверка корректности:") print(f"Наша реализация: {our_hash}") print(f"Встроенная SHA-256: {builtin_hash}") print(f"Результаты совпадают: {our_hash == builtin_hash}") |
|||
карма: 4 |
|
Ответов: 125
Рейтинг: 1
|
|||
tig-rrr писал(а): Andrej77rv писал(а):
Полную схему нигде не могу найти может код алгоритма прояснит ситуацию на Payton Увы нет. Подробную графическую схему бы найти. |
|||
карма: 1 |
|
8