Вверх ↑
Этот топик читают: Andrej77rv, Гость
Ответов: 125
Рейтинг: 1
#1: 2025-08-12 07:30:27 ЛС | профиль | цитата
Может есть такая схема алгоритма этой Хеш-функии? Понятно что есть компонент, но мне нужна именно схема для полного понимания работы.
карма: 1

0
Ответов: 4665
Рейтинг: 767
#2: 2025-08-16 08:34:38 ЛС | профиль | цитата
А описание в Википедии или на других ресурсах не подходит?
карма: 26

0
Ответов: 125
Рейтинг: 1
#3: 2025-08-19 17:11:14 ЛС | профиль | цитата
Netspirit писал(а):
А описание в Википедии или на других ресурсах не подходит?

Нет. Со схемой лучше понять можно.
карма: 1

0
Ответов: 125
Рейтинг: 1
#4: 2025-08-22 17:53:18 ЛС | профиль | цитата

Вообще не особо понятно. И описания везде по разному излагают. Не могу понять. Кто может помочь?
карма: 1

0
Ответов: 524
Рейтинг: 167
#5: 2025-08-22 18:47:03 ЛС | профиль | цитата
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

0
Ответов: 125
Рейтинг: 1
#6: 2025-08-22 19:09:13 ЛС | профиль | цитата
tig-rrr писал(а):
Andrej77rv писал(а):
Вообще не особо понятно

Задал вопрос ИИ - ответ. Может чего прояснится...


Спасибо. В начале всё понятно. Не понятно в конце. Т.е. мы берём исходное число и суммируем по модулю 2 с тем,что после преобразований и битовых сдвигов? Или нет?

--- Добавлено в 2025-08-22 19:10:16

Полную схему нигде не могу найти. Везде "обрезки".

Редактировалось 1 раз(а), последний 2025-08-22 19:10:16
карма: 1

0
Ответов: 524
Рейтинг: 167
#7: 2025-08-22 19:54:25 ЛС | профиль | цитата
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

0
Ответов: 125
Рейтинг: 1
#8: 2025-08-22 20:09:56 ЛС | профиль | цитата
tig-rrr писал(а):
Andrej77rv писал(а):
Полную схему нигде не могу найти

может код алгоритма прояснит ситуацию на Payton


Увы нет. Подробную графическую схему бы найти.
карма: 1

0
8
Сообщение
...
Прикрепленные файлы
(файлы не залиты)