mirror of
https://github.com/krahets/hello-algo.git
synced 2026-07-07 05:04:20 +00:00
deploy
This commit is contained in:
@@ -4402,7 +4402,7 @@
|
||||
<!-- Page content -->
|
||||
<h1 id="63">6.3 Алгоритмы хеширования<a class="headerlink" href="#63" title="Permanent link">¶</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 Лучший и худший случаи хеш-коллизий </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 Проектирование хеш-алгоритма<a class="headerlink" href="#632-" title="Permanent link">¶</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} & = \{ 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} & = 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 Распространенные хеш-алгоритмы </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>
|
||||
|
||||
Reference in New Issue
Block a user