This commit is contained in:
krahets
2026-04-14 18:06:19 +08:00
parent 17b2a0b630
commit cf0747ba3e
131 changed files with 604 additions and 609 deletions
+7 -7
View File
@@ -4402,7 +4402,7 @@
<!-- Page content -->
<h1 id="63">6.3 &nbsp; Алгоритмы хеширования<a class="headerlink" href="#63" title="Permanent link">&para;</a></h1>
<p>В двух предыдущих разделах мы рассмотрели принципы работы хеш-таблицы и способы обработки хеш-коллизий. Однако и открытая адресация, и метод цепочек <strong>лишь позволяют хеш-таблице корректно работать при возникновении коллизий, но не уменьшают вероятность появления самих коллизий</strong>.</p>
<p>Если хеш-коллизии происходят слишком часто, производительность хеш-таблицы резко деградирует. Как показано на рисунке 6-8, для хеш-таблицы с методом цепочек в идеальном случае пары ключ-значение равномерно распределены по всем бакетам, и это дает наилучшую эффективность поиска; в худшем же случае все пары ключ-значение оказываются в одном бакете, и временная сложность вырождается до <span class="arithmatex">\(O(n)\)</span> .</p>
<p>Если хеш-коллизии происходят слишком часто, производительность хеш-таблицы резко деградирует. Как показано на рисунке 6-8, для хеш-таблицы с методом цепочек в идеальном случае пары ключ-значение равномерно распределены по всем бакетам, и это дает наилучшую эффективность поиска. В худшем же случае все пары ключ-значение оказываются в одном бакете, и временная сложность вырождается до <span class="arithmatex">\(O(n)\)</span> .</p>
<p><img alt="Лучший и худший случаи хеш-коллизий" class="animation-figure" src="../hash_algorithm.assets/hash_collision_best_worst_condition.png" /></p>
<p align="center"> Рисунок 6-8 &nbsp; Лучший и худший случаи хеш-коллизий </p>
@@ -4421,7 +4421,7 @@
<p>На практике хеш-алгоритмы используются не только для реализации хеш-таблиц, но и во многих других областях.</p>
<ul>
<li><strong>Хранение паролей</strong>: чтобы защищать пароли пользователей, система обычно хранит не сами пароли в открытом виде, а их хеш-значения. Когда пользователь вводит пароль, система вычисляет хеш-значение введенного пароля и сравнивает его с сохраненным значением. Если они совпадают, пароль считается правильным.</li>
<li><strong>Проверка целостности данных</strong>: отправитель может вычислить хеш-значение данных и отправить его вместе с самими данными; получатель затем вычисляет хеш-значение повторно и сравнивает его с полученным. Если они совпадают, данные считаются целостными.</li>
<li><strong>Проверка целостности данных</strong>: отправитель может вычислить хеш-значение данных и отправить его вместе с самими данными. Получатель затем вычисляет хеш-значение повторно и сравнивает его с полученным. Если они совпадают, данные считаются целостными.</li>
</ul>
<p>Для приложений, связанных с криптографией, чтобы не допустить восстановления исходного пароля по хеш-значению и иных форм обратного анализа, хеш-алгоритм должен обладать более строгими свойствами безопасности.</p>
<ul>
@@ -4429,12 +4429,12 @@
<li><strong>Устойчивость к коллизиям</strong>: должно быть крайне трудно найти два разных входа, имеющих одинаковое хеш-значение.</li>
<li><strong>Эффект лавины</strong>: даже небольшое изменение во входных данных должно приводить к заметному и непредсказуемому изменению результата.</li>
</ul>
<p>Обрати внимание: <strong>"равномерное распределение" и "устойчивость к коллизиям" - это два независимых понятия</strong> , и выполнение первого не означает автоматического выполнения второго. Например, при случайном распределении входных <code>key</code> хеш-функция <code>key % 100</code> может выдавать достаточно равномерное распределение. Однако этот хеш-алгоритм слишком прост: все <code>key</code> с одинаковыми двумя последними цифрами будут иметь одинаковый результат, а значит, по хеш-значению можно легко подобрать подходящие <code>key</code> и, например, взломать пароль.</p>
<p>Обрати внимание: <strong>«равномерное распределение» и «устойчивость к коллизиям» - это два независимых понятия</strong> , и выполнение первого не означает автоматического выполнения второго. Например, при случайном распределении входных <code>key</code> хеш-функция <code>key % 100</code> может выдавать достаточно равномерное распределение. Однако этот хеш-алгоритм слишком прост: все <code>key</code> с одинаковыми двумя последними цифрами будут иметь одинаковый результат, а значит, по хеш-значению можно легко подобрать подходящие <code>key</code> и, например, взломать пароль.</p>
<h2 id="632-">6.3.2 &nbsp; Проектирование хеш-алгоритма<a class="headerlink" href="#632-" title="Permanent link">&para;</a></h2>
<p>Разработка хеш-алгоритма - это сложная задача, в которой нужно учитывать множество факторов. Однако для некоторых нетребовательных сценариев мы можем спроектировать и несколько простых хеш-алгоритмов.</p>
<ul>
<li><strong>Аддитивный хеш</strong>: складываем ASCII-коды всех символов входной строки и используем полученную сумму как хеш-значение.</li>
<li><strong>Мультипликативный хеш</strong>: используем "некоррелированность" умножения; на каждом шаге умножаем текущее значение на константу и добавляем ASCII-код очередного символа.</li>
<li><strong>Мультипликативный хеш</strong>: используем «некоррелированность» умножения. На каждом шаге умножаем текущее значение на константу и добавляем ASCII-код очередного символа.</li>
<li><strong>XOR-хеш</strong>: последовательно накапливаем элементы входных данных в одном хеш-значении через операцию XOR.</li>
<li><strong>Ротационный хеш</strong>: последовательно накапливаем ASCII-коды символов, причем перед каждым накоплением выполняем циклический сдвиг хеш-значения.</li>
</ul>
@@ -5021,7 +5021,7 @@
\text{hash} &amp; = \{ 0, 3, 6, 0, 3, 6, 0, 3, 6, 0, 3, 6,\dots \}
\end{aligned}
\]</div>
<p>Если входные <code>key</code> как раз удовлетворяют такому распределению в виде арифметической прогрессии, то хеш-значения начнут скучиваться, а это усугубит хеш-коллизии. Теперь предположим, что мы заменили <code>modulus</code> на простое число <span class="arithmatex">\(13\)</span> ; поскольку между <code>key</code> и <code>modulus</code> нет общих делителей, равномерность распределения хеш-значений заметно улучшится.</p>
<p>Если входные <code>key</code> как раз удовлетворяют такому распределению в виде арифметической прогрессии, то хеш-значения начнут скучиваться, а это усугубит хеш-коллизии. Теперь предположим, что мы заменили <code>modulus</code> на простое число <span class="arithmatex">\(13\)</span>. Поскольку между <code>key</code> и <code>modulus</code> нет общих делителей, равномерность распределения хеш-значений заметно улучшится.</p>
<div class="arithmatex">\[
\begin{aligned}
\text{modulus} &amp; = 13 \newline
@@ -5037,7 +5037,7 @@
<p>На протяжении почти ста лет хеш-алгоритмы непрерывно развивались и оптимизировались. Одни исследователи старались повысить их производительность, а другие исследователи и хакеры сосредоточивались на поиске уязвимостей в их безопасности. В таблице 6-2 приведены распространенные хеш-алгоритмы, которые часто встречаются в реальных приложениях.</p>
<ul>
<li>MD5 и SHA-1 уже многократно были успешно атакованы, поэтому они выведены из большинства сценариев, где требуется безопасность.</li>
<li>SHA-256 из семейства SHA-2 является одним из самых надежных хеш-алгоритмов; на сегодняшний день не известно успешных практических атак, поэтому он широко используется в самых разных протоколах и системах безопасности.</li>
<li>SHA-256 из семейства SHA-2 является одним из самых надежных хеш-алгоритмов. На сегодняшний день не известно успешных практических атак, поэтому он широко используется в самых разных протоколах и системах безопасности.</li>
<li>SHA-3 по сравнению с SHA-2 требует меньших затрат на реализацию и обеспечивает более высокую вычислительную эффективность, но на данный момент распространен слабее, чем семейство SHA-2.</li>
</ul>
<p align="center"> Таблица 6-2 &nbsp; Распространенные хеш-алгоритмы </p>
@@ -5096,7 +5096,7 @@
<p>Мы знаем, что <code>key</code> в хеш-таблице могут быть целыми числами, вещественными числами, строками и другими типами данных. Языки программирования обычно предоставляют встроенные хеш-алгоритмы для этих типов, чтобы вычислять индексы бакетов в хеш-таблице. Возьмем Python: в нем можно вызвать функцию <code>hash()</code> , чтобы вычислить хеш-значения для различных типов данных.</p>
<ul>
<li>Хеш-значение целого числа и булева значения совпадает с самим значением.</li>
<li>Вычисление хеш-значений для вещественных чисел и строк устроено сложнее; интересующиеся читатели могут изучить это самостоятельно.</li>
<li>Вычисление хеш-значений для вещественных чисел и строк устроено сложнее. Интересующиеся читатели могут изучить это самостоятельно.</li>
<li>Хеш-значение кортежа получается путем хеширования каждого элемента, а затем объединения этих хеш-значений в одно итоговое значение.</li>
<li>Хеш-значение объекта обычно строится на основе его адреса в памяти. Если переопределить метод хеширования объекта, можно реализовать вычисление хеша по содержимому.</li>
</ul>