В математике и вычислениях универсальное хеширование (в рандомизированном алгоритме или структуре данных ) относится к выбору хеш-функции случайным образом из семейства хеш-функций с определенным математическим свойством (см. определение ниже). Это гарантирует низкое количество коллизий в ожидании , даже если данные выбраны злоумышленником. Известно много универсальных семейств (для хеширования целых чисел, векторов, строк), и их оценка часто очень эффективна. Универсальное хеширование имеет многочисленные применения в информатике, например, в реализациях хеш-таблиц , рандомизированных алгоритмов и криптографии .
Предположим, мы хотим сопоставить ключи из некоторой вселенной с ячейками (помеченными ). Алгоритм должен будет обрабатывать некоторый набор данных ключей , который заранее неизвестен. Обычно целью хеширования является получение небольшого количества коллизий (ключи из этого попадают в одну и ту же ячейку). Детерминированная хеш-функция не может дать никаких гарантий в состязательной обстановке, если , поскольку злоумышленник может выбрать именно прообраз ячейки. Это означает, что все ключи данных попадают в одну и ту же ячейку, что делает хеширование бесполезным. Кроме того, детерминированная хеш-функция не допускает повторного хеширования : иногда входные данные оказываются плохими для хеш-функции (например, слишком много коллизий), поэтому хотелось бы изменить хеш-функцию.
Решение этих проблем — выбрать функцию случайным образом из семейства хэш-функций. Семейство функций называется универсальным семейством, если, .
Другими словами, любые два различных ключа вселенной сталкиваются с вероятностью не более , когда хэш-функция выводится равномерно случайным образом из . Это именно та вероятность столкновения, которую мы ожидали бы, если бы хэш-функция назначала действительно случайные хэш-коды каждому ключу.
Иногда определение смягчается постоянным множителем, требуя только вероятности столкновения, а не . Эта концепция была введена Картером и Вегманом [1] в 1977 году и нашла многочисленные применения в информатике (см., например , [2] ) .
Если у нас есть верхняя граница вероятности столкновения, мы говорим, что у нас есть -почти универсальность. Так, например, универсальное семейство имеет -почти универсальность.
Многие, но не все, универсальные семейства обладают следующим более сильным свойством равномерной разности :
Обратите внимание, что определение универсальности касается только того , , что учитывает столкновения. Свойство равномерной разности сильнее.
(Аналогично, универсальное семейство может быть универсальным XOR , если значение равномерно распределено в , где — побитовая операция «исключающее ИЛИ». Это возможно только в том случае, если — степень двойки.)
Еще более сильным условием является попарная независимость : это свойство имеет место, когда вероятность того, что хэширование любой пары значений хэша будет таким, как если бы они были совершенно случайными: . Попарную независимость иногда называют сильной универсальностью.
Другое свойство — однородность. Мы говорим, что семейство однородно, если все значения хэша одинаково вероятны: для любого значения хэша . Универсальность не подразумевает однородность. Однако сильная универсальность подразумевает однородность.
Учитывая семейство со свойством равномерного расстояния, можно создать попарно независимое или строго универсальное хеш-семейство, добавив равномерно распределенную случайную константу со значениями в к хеш-функциям. (Аналогично, если является степенью двойки, мы можем добиться попарной независимости от универсального хеш-семейства XOR, выполнив исключающее или с равномерно распределенной случайной константой.) Поскольку сдвиг на константу иногда не имеет значения в приложениях (например, хеш-таблицах), тщательное различие между свойством равномерного расстояния и попарной независимостью иногда не проводится. [3]
Для некоторых приложений (например, хэш-таблиц) важно, чтобы наименее значимые биты хэш-значений также были универсальными. Когда семейство является строго универсальным, это гарантируется: если является строго универсальным семейством с , то семейство, составленное из функций для всех , также строго универсально для . К сожалению, то же самое не относится к (просто) универсальным семействам. Например, семейство, составленное из функции тождества , очевидно, универсально, но семейство, составленное из функции , не является универсальным.
UMAC и Poly1305-AES , а также несколько других алгоритмов кода аутентификации сообщений основаны на универсальном хешировании. [4] [5] В таких приложениях программное обеспечение выбирает новую хеш-функцию для каждого сообщения на основе уникального одноразового номера для этого сообщения.
Несколько реализаций хэш-таблиц основаны на универсальном хэшировании. В таких приложениях обычно программное обеспечение выбирает новую хэш-функцию только после того, как замечает, что столкнулось «слишком много» ключей; до тех пор одна и та же хэш-функция продолжает использоваться снова и снова. (Некоторые схемы разрешения коллизий, такие как динамическое идеальное хэширование , выбирают новую хэш-функцию каждый раз, когда происходит столкновение. Другие схемы разрешения коллизий, такие как хэширование кукушки и хэширование с двумя вариантами , допускают несколько коллизий перед выбором новой хэш-функции). Обзор самых быстрых известных универсальных и строго универсальных хэш-функций для целых чисел, векторов и строк можно найти в. [6]
Для любого фиксированного набора ключей использование универсального семейства гарантирует следующие свойства.
Поскольку указанные выше гарантии выполняются для любого фиксированного набора , они выполняются, если набор данных выбирается противником. Однако противник должен сделать этот выбор до (или независимо от) случайного выбора алгоритмом хэш-функции. Если противник может наблюдать случайный выбор алгоритма, случайность не имеет смысла, и ситуация такая же, как и при детерминированном хэшировании.
Вторая и третья гарантии обычно используются в сочетании с повторным хэшированием . Например, рандомизированный алгоритм может быть подготовлен для обработки некоторого количества столкновений. Если он наблюдает слишком много столкновений, он выбирает другое случайное число из семейства и повторяет. Универсальность гарантирует, что число повторений является геометрической случайной величиной .
Поскольку любые компьютерные данные можно представить в виде одного или нескольких машинных слов, обычно требуются хеш-функции для трех типов доменов: машинные слова («целые числа»); векторы машинных слов фиксированной длины; и векторы переменной длины («строки»).
В этом разделе рассматривается случай хеширования целых чисел, которые помещаются в машинные слова; таким образом, такие операции, как умножение, сложение, деление и т. д., являются дешевыми инструкциями машинного уровня. Пусть вселенная, которая должна быть хеширована, будет .
Первоначальное предложение Картера и Вегмана [1] состояло в том, чтобы выбрать простое число и определить
где — случайно выбранные целые числа по модулю . (Это одна итерация линейного конгруэнтного генератора .)
Чтобы увидеть, что это универсальное семейство, обратите внимание, что оно выполняется только тогда, когда
для некоторого целого числа между и . Так как , если их разность ненулевая и имеет обратный по модулю . Решение для дает
Возможны варианты выбора (поскольку исключено) и, варьируясь в допустимом диапазоне, возможные ненулевые значения для правой стороны. Таким образом, вероятность столкновения равна
Другой способ увидеть универсальное семейство — через понятие статистического расстояния . Запишите разницу как
Так как ненулевое и равномерно распределено в , то отсюда следует, что по модулю также равномерно распределено в . Распределение, таким образом, почти равномерно, с точностью до разницы в вероятности между выборками. В результате статистическое расстояние до однородного семейства равно , которое становится пренебрежимо малым, когда .
Семейство более простых хэш-функций
является лишь приблизительно универсальным: для всех . [1] Более того, этот анализ почти точный; Картер и Вегман [1] показывают, что всякий раз, когда .
Современным решением для хеширования целых чисел является схема умножения-сдвига, описанная Дитцфельбингером и др. в 1997 году. [8] Избегая модульной арифметики, этот метод гораздо проще в реализации и также работает значительно быстрее на практике (обычно по крайней мере в четыре раза [9] ). Схема предполагает, что количество ячеек является степенью двойки, . Пусть будет количеством бит в машинном слове. Затем хеш-функции параметризуются по нечетным положительным целым числам (которые помещаются в слово битов). Чтобы оценить , умножьте на по модулю и затем сохраните биты старшего порядка в качестве хеш-кода. В математической нотации это
Эта схема не удовлетворяет свойству равномерной разности и является лишь -почти-универсальной ; для любого , .
Чтобы понять поведение хэш-функции, обратите внимание, что если и имеют одинаковые биты высшего порядка «M», то имеет либо все 1, либо все 0 в качестве своих битов высшего порядка M (в зависимости от того, больше или ). Предположим, что младший установленный бит из появляется в позиции . Поскольку является случайным нечетным целым числом, а нечетные целые числа имеют обратные в кольце , следует, что будет равномерно распределено среди -битных целых чисел с младшим установленным битом в позиции . Вероятность того, что эти биты все равны 0 или все равны 1, составляет, таким образом, не более . С другой стороны, если , то биты высшего порядка M из содержат как 0, так и 1, поэтому определенно, что . Наконец, если то бит из равен 1 и тогда и только тогда, когда биты также равны 1, что происходит с вероятностью .
Этот анализ является точным, как можно показать на примере и . Чтобы получить действительно «универсальную» хэш-функцию, можно использовать схему умножения-сложения-сдвига, которая выбирает биты более высокого порядка
где — случайное положительное целое число с , а — случайное неотрицательное целое число с . Для этого требуется выполнение арифметических операций с -битными беззнаковыми целыми числами. Эта версия умножения-сдвига принадлежит Дицфельбингеру и позднее была более точно проанализирована Вёльфелем. [10]
В этом разделе рассматривается хеширование вектора машинных слов фиксированной длины. Интерпретируйте входные данные как вектор машинных слов (целые числа бит каждое). Если — универсальное семейство со свойством равномерной разности, то следующее семейство (восходящее к Картеру и Вегману [1] ) также обладает свойством равномерной разности (и, следовательно, является универсальным):
Если — степень двойки, то можно заменить суммирование на исключающее ИЛИ. [11]
На практике, если доступна арифметика двойной точности, она реализуется с помощью семейства хэш-функций с множественным сдвигом. [12] Инициализируем хэш-функцию вектором случайных нечетных целых чисел на битах каждый. Затем, если число ячеек равно для :
Можно сократить вдвое количество умножений, что на практике примерно означает двукратное ускорение. [11] Инициализируйте хэш-функцию вектором случайных нечетных целых чисел на битах. Следующее семейство хэшей является универсальным: [13]
Если операции двойной точности недоступны, можно интерпретировать входные данные как вектор полуслов ( -битных целых чисел). Тогда алгоритм будет использовать умножения, где было числом полуслов в векторе. Таким образом, алгоритм работает со «скоростью» одного умножения на слово входных данных.
Эту же схему можно использовать для хеширования целых чисел, интерпретируя их биты как векторы байтов. В этом варианте векторная техника известна как табуляция хеширования и она предоставляет практическую альтернативу универсальным схемам хеширования на основе умножения. [14]
Также возможна сильная универсальность на высокой скорости. [15] Инициализируйте хэш-функцию вектором случайных целых чисел на битах. Вычислите
Результат строго универсален по битам. Экспериментально было обнаружено, что он работает на 0,2 цикла ЦП на байт на последних процессорах Intel для .
Это относится к хешированию вектора машинных слов переменного размера . Если длина строки может быть ограничена небольшим числом, лучше всего использовать векторное решение сверху (концептуально дополняя вектор нулями до верхней границы). Требуемое пространство равно максимальной длине строки, но время вычисления равно только длине . Пока нули запрещены в строке, дополнение нулями можно игнорировать при вычислении хеш-функции, не влияя на универсальность. [11] Обратите внимание, что если нули разрешены в строке, то может быть лучше добавить фиктивный ненулевой (например, 1) символ ко всем строкам перед заполнением: это гарантирует, что универсальность не будет затронута. [15]
Теперь предположим, что мы хотим хэшировать , где хорошая граница не известна априори. Универсальное семейство, предложенное в [12], рассматривает строку как коэффициенты полинома по модулю большого простого числа. Если , пусть будет простым числом и определите:
Используя свойства модульной арифметики, вышеприведенное можно вычислить без создания больших чисел для больших строк следующим образом: [16]
uint hash ( String x , int a , int p ) uint h = INITIAL_VALUE для ( uint i = 0 ; i < x . length ; ++ i ) h = (( h * a ) + x [ i ]) mod p return h
Этот хэш-функция Рабина-Карпа основана на линейном конгруэнтном генераторе . [17] Вышеуказанный алгоритм также известен как мультипликативная хэш-функция . [18] На практике оператор mod и параметр p можно полностью исключить, просто допустив переполнение целого числа, поскольку это эквивалентно mod ( Max-Int-Value + 1) во многих языках программирования. В таблице ниже показаны значения, выбранные для инициализации h и a для некоторых популярных реализаций.
Рассмотрим две строки и пусть будет длиной более длинной из них; для анализа более короткая строка концептуально дополняется нулями до длины . Столкновение перед применением подразумевает, что является корнем многочлена с коэффициентами . Этот многочлен имеет не более корней по модулю , поэтому вероятность столкновения не более . Вероятность столкновения через случайность приводит общую вероятность столкновения к . Таким образом, если простое число достаточно велико по сравнению с длиной хэшированных строк, семейство очень близко к универсальному (по статистическому расстоянию ).
Другие универсальные семейства хеш-функций, используемые для хеширования строк неизвестной длины в хеш-значения фиксированной длины, включают отпечаток Рабина и Бужаш .
Чтобы уменьшить вычислительные потери модульной арифметики, на практике используются три приема: [11]
{{cite book}}
: CS1 maint: multiple names: authors list (link)