Универсальное хеширование
Универса́льное хеши́рование (англ. Universal hashing) — это вид хеширования, при котором используется не одна конкретная хеш-функция, а происходит выбор из заданного семейства по случайному алгоритму[1][2]. Такой подход обеспечивает равномерное хеширование: для очередного ключа вероятности помещения его в любую ячейку совпадают. Известно несколько семейств универсальных хеш-функций, которые имеют многочисленные применения в информатике, в частности в хеш-таблицах, вероятностных алгоритмах и криптографии.
Введение
Впервые понятие универсального хеширования было введено в статье[1] Картера и Вегмана в 1979 году.
Изначально универсальное хеширование было разработано как независящий от входных данных алгоритм, работающий в среднем за линейное время и предназначенный для хранения и извлечения ключей из хеш-таблицы. Под независимостью от входных данных подразумевается следующее: для любой последовательности входных данных соответствующие хеш-значения элементов последовательности будут равномерно распределены по хеш-таблице. При выполнении этого условия среднее время работы алгоритма для любых данных оказывается сравнимым со временем работы хеш-функции, используемой для распределения заранее известных данных[1].
Созданный алгоритм универсального хеширования представлял собой случайный выбор хеш-функции из некоторого набора хеш-функций(называемого универсальным семейством хеш-функций), обладающих определёнными свойствами. Авторами было показано, что в случае универсального хеширования число обращений к хеш-таблице (в среднем по всем функциям из семейства) для произвольных входных данных оказывается очень близким теоретическому минимуму для случая фиксированной хеш-функции со случайно распределёнными входными данными[1].
Используя универсальное хеширование, авторы хотели[1]:
- Избавиться от необходимости предполагать вид входных данных.
- Устранить зависимость времени работы хеширования от вида входных данных.
- Добиться уменьшения числа коллизий.
В работе[1] Вегмана и Картера универсальное хеширование было применено для построения хеш-таблицы, хотя позднее универсальное хеширование получило применение и в других областях(см. #Применение).
Определение универсального семейства хеш-функций
Пусть [math]\displaystyle{ U }[/math] — множество ключей, [math]\displaystyle{ H }[/math] — конечное множество хеш-функций, отображающих [math]\displaystyle{ U }[/math] во множество [math]\displaystyle{ \left \{ 0,1,..,m-1 \right \} }[/math]. Возьмем произвольные [math]\displaystyle{ h \in H }[/math] и [math]\displaystyle{ x,y \in U }[/math] и определим функцию коллизий [math]\displaystyle{ \delta _h (x,y) }[/math]:
[math]\displaystyle{ \delta _h (x,y) = \begin{cases} 1, & \mbox{if } x \ne y \mbox{ and } h(x) = h(y)\\ 0, & \mbox{otherwise} \end{cases} }[/math]
Если [math]\displaystyle{ \delta _h (x,y) = 1 }[/math], то говорят, что имеет место коллизия. Можно определить функцию коллизии не для отдельных элементов [math]\displaystyle{ x,y,h }[/math], а для целого множества элементов — для этого надо произвести сложение функций коллизий по всем элементам из множества. Например, если [math]\displaystyle{ H }[/math] — множество хеш-функций, [math]\displaystyle{ x \in U }[/math], [math]\displaystyle{ S \subset U }[/math], то для функции коллизии [math]\displaystyle{ \delta _H (x,S) }[/math] получим:
[math]\displaystyle{ \delta _H (x,S) = \sum_{h \in H} \sum_{y \in S} \delta _h (x,y) }[/math]
Причём порядок суммирования не имеет значения.
Определение. Семейство хеш-функций [math]\displaystyle{ H }[/math] называется универсальным[1], если
- [math]\displaystyle{ \forall x, y \in U \longrightarrow \delta _H (x,S) = \frac{\left | H \right |}{m}. }[/math]
Можно дать другое определение, эквивалентное данному.
Определение. Семейство хеш-функций [math]\displaystyle{ H }[/math] называется универсальным[3][4], если
- [math]\displaystyle{ \forall x, y \in U, ~ x\ne y: ~~ \Pr_{h\in H} [h(x) = h(y)] \le \frac{1}{m} }[/math]
Свойства универсального семейства хеш-функций в случае его применения к хеш-таблицам
Следующая теорема определяет нижнюю границу функции [math]\displaystyle{ \delta _h (x,y) }[/math] для произвольного семейства хеш-функций[1].
Теорема 1.Для любого семейства(не обязательно универсального) хеш-функций [math]\displaystyle{ H }[/math] существуют [math]\displaystyle{ x,y \in U }[/math] такие, что
[math]\displaystyle{ \delta _H (x,S) \gt \frac{\left | H \right |}{m} - \frac{\left | H \right |}{\left | U \right |} }[/math]
Из теоремы 1 следует, что нижняя граница функции коллизии близка к [math]\displaystyle{ \frac{\left | H \right |}{m} }[/math] в случае, когда [math]\displaystyle{ \left | U \right | }[/math] много больше [math]\displaystyle{ m }[/math]. В действительности, часто так и бывает. Например, пусть компилятор ставит в соответствие тысяче переменных последовательности из семи английских букв. Тогда [math]\displaystyle{ m = 1000 }[/math], а [math]\displaystyle{ \left | U \right | = 26^7 }[/math]
Для универсального семейства хеш-функций это означает, что верхняя и нижняя границы функции коллизии довольно близки[1].
В статье[1] универсальное хеширование применялось для организации хеш-таблиц с разрешением коллизий методом цепочек. Ниже изложены теоремы, дающие некоторые оценки значений функции коллизии и производительности хеширования в случае организации хеш-таблицы с разрешением коллизий методом цепочек.
Пусть [math]\displaystyle{ H }[/math] — универсальное семейство хеш-функций, отображающих множество ключей [math]\displaystyle{ U }[/math] во множество [math]\displaystyle{ \left \{ 0,1,..,m-1 \right \} }[/math]. Пусть для организации хеш-таблицы с разрешением коллизий методом цепочек, то есть с помощью линейного списка, используется некоторая случайная функция [math]\displaystyle{ h \in H }[/math]. Если хеш-функция [math]\displaystyle{ h }[/math] отобразила в таблицу подмножество [math]\displaystyle{ S \subset U }[/math] ключей, то средняя длина связанных списков будет равна [math]\displaystyle{ 1 + \delta _h (x,S) }[/math]. Следующая теорема дает оценку для функции коллизий в случае универсального семейства.
Теорема 2.[1] Пусть [math]\displaystyle{ x }[/math] — произвольный элемент множества [math]\displaystyle{ U }[/math], [math]\displaystyle{ S }[/math] — произвольное подмножество множества [math]\displaystyle{ U }[/math]. Пусть функция [math]\displaystyle{ h }[/math] случайно выбирается из универсального семейства хеш-функций [math]\displaystyle{ H }[/math]. Тогда имеет место следующая оценка:
[math]\displaystyle{ \delta _h (x,S) \leqslant \frac{\left | S \right |}{m} }[/math]
Этот результат можно использовать для вычисления ожидаемой производительности хеш-функции для последовательности из [math]\displaystyle{ R }[/math] запросов. Но сначала надо уточнить, что подразумевается под производительностью. Для этого нужно определить понятие стоимости — под стоимостью одного запроса к хеш-таблице по ключу [math]\displaystyle{ x }[/math] понимается число [math]\displaystyle{ 1 + \delta _h (x,S) }[/math], где [math]\displaystyle{ S }[/math] — множество ранее помещённых в таблицу ключей, а в самой хеш-таблице используется метод цепочек(то есть это число операций, необходимое для выполнения одного запроса). Стоимость [math]\displaystyle{ C(h,R) }[/math] хеш-функции [math]\displaystyle{ h }[/math] на последовательности запросов [math]\displaystyle{ R }[/math] есть сумма стоимостей отдельных запросов, идущих в последовательности, указанной в [math]\displaystyle{ R }[/math]. Стоимость, по сути, представляет количественную меру производительности.
Теорема 3.[1] Пусть [math]\displaystyle{ x }[/math] Пусть [math]\displaystyle{ R }[/math] — это последовательность из [math]\displaystyle{ r }[/math] запросов, содержащая [math]\displaystyle{ k }[/math] вставок. Пусть [math]\displaystyle{ H }[/math] — универсальное семейство хеш-функций. Тогда для случайно выбранной из [math]\displaystyle{ H }[/math] хеш-функции [math]\displaystyle{ h }[/math] справедливо неравенство:
[math]\displaystyle{ M[C(h,R)] \leqslant r(1+\frac{k}{m}) }[/math].
Довольно часто[1] известно приближенное число ключей, которое необходимо хранить в хеш-таблице. Тогда, можно подобрать размер [math]\displaystyle{ m }[/math] хеш-таблицы таким образом, чтобы отношение [math]\displaystyle{ \frac{k}{m} }[/math] было приблизительно равно 1. Значит, согласно теореме 3, ожидаемая стоимость исполнения последовательности запросов [math]\displaystyle{ R }[/math] будет прямо пропорционально числу запросов [math]\displaystyle{ r }[/math]. Причём это справедливо для любой последовательности запросов [math]\displaystyle{ R }[/math], а не для некоторой «средней» последовательности.
Таким образом, для любой случайно выбранной из универсального семейства хеш-функции её производительность оказывается достаточно хорошей. Остаётся вопрос о том, нужно ли менять хеш-функцию с течением времени, а если нужно, то как часто.
В случае с хеш-таблицами частая смена хеш-функций ведёт к большим накладным расходам. Например, если хеш-таблица имеет очень большие размеры, то при смене хеш-функции потребуется перемещение большого объёма данных. Существует несколько стратегий выбора хеш-функции. Наиболее простая стратегия состоит в том, чтобы в начале работы случайно выбрать хеш-функцию [math]\displaystyle{ h }[/math] и не менять её вплоть до конца работы. Однако в этом случае производительность хеш-функции оказывается значительно ниже ожидаемой[1]. Другая стратегия состоит в том, чтобы время от времени подсчитывать число коллизий и менять хеш-функцию, если это число значительно превышает ожидаемое. Такой подход обеспечивает хорошую производительность, при условии, что хеш-функция выбирается случайно.
Построение универсального семейства хеш-функций
Этот раздел посвящён построению универсальных семейств хеш-функций, из которых случайным образом выбирается хеш-функция.
Существует несколько семей универсальных хеш-функций, которые различаются тем, для каких данных предназначены эти функции: скаляры (хеширование чисел), векторы фиксированной длины (хеширование векторов), векторы переменной длины (хеширование строк).
Хеширование чисел
Выберем простое число [math]\displaystyle{ p }[/math] и рассмотрим поле [math]\displaystyle{ \mathbb {Z}_p = \left \{ 0,1, ...,p-1 \right \} }[/math] и его мультипликативную группу [math]\displaystyle{ \mathbb {Z} _p^* = \left \{ 1,..,p-1 \right \} }[/math].
Теорема. Множество функций вида [math]\displaystyle{ H_{p,m} = \left \{ h_{a,b}: a \in \mathbb {Z} _p^*,b \in \mathbb {Z} _p \right \} }[/math], где [math]\displaystyle{ h_{a,b}(x) = ((ax+b) \mod p) \mod m }[/math], является универсальным (Это было показано в работе Картера и Вегмана[1]).
Действительно, [math]\displaystyle{ h(x) = h(y) }[/math] только при
- [math]\displaystyle{ ax+b \equiv ay + b + i\cdot m \pmod{p}, \; \forall i \in \left \{ 0,1, ..., p/m \right \}. }[/math]
Если [math]\displaystyle{ x \neq y }[/math], то разность [math]\displaystyle{ x-y \neq 0 }[/math] и может быть обращена по модулю [math]\displaystyle{ p }[/math]. Отсюда можно получить
- [math]\displaystyle{ a \equiv i\cdot m \cdot (x-y)^{-1} \pmod{p}. }[/math]
Это уравнение имеет [math]\displaystyle{ p-1 }[/math] решений, причем правая часть может принимать [math]\displaystyle{ \lfloor p/m \rfloor }[/math] значений. Таким образом, вероятность коллизий равна
- [math]\displaystyle{ \lfloor p/m \rfloor / (p-1) }[/math],
которая стремится к [math]\displaystyle{ 1/m }[/math] при увеличении [math]\displaystyle{ p }[/math]. [math]\displaystyle{ \Box }[/math]
Хеширование векторов
Пусть число [math]\displaystyle{ m }[/math] является простым. Пусть входные данные [math]\displaystyle{ x }[/math] представлены как последовательность [math]\displaystyle{ r+1 }[/math] элементов, принадлежащих [math]\displaystyle{ \left \{ 0,1,..,p-1 \right \} }[/math], то есть [math]\displaystyle{ x = \left \langle x_0, x_1, ..., x_r \right \rangle }[/math].
Для всех последовательностей вида [math]\displaystyle{ a = \left \langle a_0, a_1, ..., a_r \right \rangle, a_i \in \mathbb {Z}_p, i = \overline{0,r} }[/math] рассмотрим функцию [math]\displaystyle{ h_a }[/math] вида
- [math]\displaystyle{ h_a(x) =\sum^{r}_{i=0} {a_ix_i} \mod m }[/math]
Положим, что [math]\displaystyle{ H = \bigcup_a h_a }[/math]
Видно, что [math]\displaystyle{ H }[/math] содержит [math]\displaystyle{ m^{r+1} }[/math]
Теорема. Множество [math]\displaystyle{ H }[/math] является универсальным семейством хеш-функций (Это также было показано Картером и Вегманом[1]).
Действительно, если [math]\displaystyle{ x = \left \langle x_0, x_1, ..., x_r \right \rangle, y = \left \langle y_0, y_1, ..., y_r \right \rangle }[/math], причём [math]\displaystyle{ x_0 \neq y_0 }[/math], то [math]\displaystyle{ h_a(x) = h_a(y) }[/math] тогда и только тогда, когда
- [math]\displaystyle{ a_0(x_0 - y_0) = - \sum^{r}_{i=1} {a_i(x_i - y_i)} \mod m }[/math]
Поскольку [math]\displaystyle{ x_0 - y_0 \not\equiv 0 \mod m }[/math], то [math]\displaystyle{ \forall \left \langle a_1, ..., a_r \right \rangle, \exists ! a_0 }[/math] при котором выполняется указанное уравнение. Количество таких последовательностей равно [math]\displaystyle{ m^r }[/math], а значит и количество функций из [math]\displaystyle{ H }[/math], не различающих [math]\displaystyle{ x }[/math] и [math]\displaystyle{ y }[/math] также равно [math]\displaystyle{ m^r }[/math]. Но [math]\displaystyle{ m^r = \frac{\left | H \right |}{m} }[/math], откуда и следует универсальность. [math]\displaystyle{ \Box }[/math]
Это семейство функций можно обобщить[5]. Рассмотрим семейство функций [math]\displaystyle{ H_{p,m} = \left \{ h_{a,b}: a \in \mathbb {Z} _p^*,b \in \mathbb {Z} _p \right \} }[/math] и для вектора [math]\displaystyle{ x = \left \langle x_0, x_1, ..., x_r \right \rangle }[/math] рассмотрим хеш-функцию
- [math]\displaystyle{ h(\bar{x}) = \left( \sum_{i=0}^{k-1} h_i(x_i) \right)\,\bmod~m }[/math], где [math]\displaystyle{ h_i \in H }[/math]
Тогда совокупность таких функций также будет являться универсальным семейством.
Хеширование строк
В этом случае входными данными для хеш-функции являются вектора, длина которых не является фиксированной величиной. Если можно ограничить длину всех векторов некоторым числом [math]\displaystyle{ L }[/math], то можно применить подход, который был использован для векторов фиксированной длины. При этом, если длина вектора [math]\displaystyle{ l }[/math] меньше [math]\displaystyle{ L }[/math], то можно дополнить вектор нулями так, чтобы его длина стала равна [math]\displaystyle{ L }[/math][5]
Теперь предположим, что нельзя заранее подобрать число [math]\displaystyle{ L }[/math], ограничивающее длину всех векторов. Тогда можно предложить такой подход[6] : пусть имеется входной вектор [math]\displaystyle{ \bar{x} = (x_0,\dots, x_\ell), \forall x_i \in \left \{ 0, 1, ..., u-1 \right \} }[/math]. Положим, что [math]\displaystyle{ p \ge \max \{ u, m \} }[/math] и будем рассматривать компоненты вектора как коэффициенты многочлена: [math]\displaystyle{ x_l \cdot a^l + x_{l-1} \cdot a^{l-1} + ... x_{1} \cdot a^{1} + x_{0} \cdot a^{0}, }[/math] где [math]\displaystyle{ a \in \left \{ 0, 1, ..., p-1 \right \} }[/math].
Тогда для векторов переменной длины универсальная хеш-функция может быть определена следующим образом:
- [math]\displaystyle{ h_a(\bar{x}) = h_{a}^\mathrm{int} \left( \big(\sum_{i=0}^\ell x_i\cdot a^i \big) \bmod ~p \right), }[/math]
где
- [math]\displaystyle{ h_{a}^\mathrm{int}:\left \{ 0,1,..,p-1 \right \} \rightarrow\left \{ 0,1,..,m-1 \right \} }[/math]
является универсальной хеш-функцией для числовых аргументов.
Применение
Коды аутентификации сообщений UMAC, Poly1305-AES и некоторые другие основаны на использовании универсального хеширования[7][8][9]. В этих кодах для каждого сообщения выбирается своя хеш-функция в зависимости от его одноразового уникального номера.
Универсальное семейство хеш-функций может быть использовано в том случае, когда требуется наличие большого числа «хороших» хеш-функций. Программисты часто тратят много времени, проводя анализ работы хеш-функций на различных данных и пытаясь выбрать подходящую[10]. Время поиска можно уменьшить, взяв универсальное семейство хеш-функций и выбрав случайно несколько функций из этого семейства[1].
Теоретическая значимость универсального хеширования состоит в том, что оно даёт «хорошую» границу для средней производительности алгоритмов, использующих хеширование. Например, универсальное хеширование было применено в алгоритмах, представленных в работах [11] [12] [13].
В теоретической криптографии было показано, что с помощью универсальных хеш-функций можно построить систему аутентификации с предельно достижимой секретностью[1]. Примером универсальной хеш-функцией с доказанной криптографической стойкостью является хеш-функция SWIFFT.
Более того, одним из наиболее важных приложений универсального хеширования является скоординированная выборка[2].
См. также
Примечания
- ↑ 1,00 1,01 1,02 1,03 1,04 1,05 1,06 1,07 1,08 1,09 1,10 1,11 1,12 1,13 1,14 1,15 1,16 1,17 Carter, Larry; Wegman, Mark N. Universal Classes of Hash Functions (англ.) // Journal of Computer and System Sciences : journal. — 1979. — Vol. 18, no. 2. — P. 143—154. — doi:10.1016/0022-0000(79)90044-8.
- ↑ 2,0 2,1 Thorup, Mikkel, Speed Hashing for Integers and Strings (недоступная ссылка), Cornell University Library, July 15, 2014
- ↑ Motwani, Rajeev; Raghavan, Prabhakar. Randomized Algorithms (неопр.). — Cambridge University Press, 1995. — С. 216—217. — ISBN 0-521-47465-5.
- ↑ Cormen, 2001, pp. 234—235.
- ↑ 5,0 5,1 Mikkel Thorup. String hashing for linear probing // [1]. — 2009. — P. Proc. 20th ACM-SIAM Symposium on Discrete Algorithms (SODA), 655–664. — doi:10.1137/1.9781611973068.72. , section 5.3
- ↑ Dietzfelbinger, Martin; Gil, Joseph; Matias, Yossi; Pippenger, Nicholas(1992). «Polynomial Hash Functions Are Reliable (Extended Abstract)». Proc. 19th International Colloquium on Automata, Languages and Programming (ICALP). pp. 235—246
- ↑ * David Wagner, ed. «Advances in Cryptology — CRYPTO 2008» Архивная копия от 29 мая 2016 на Wayback Machine. p. 145.
- ↑ * Jean-Philippe Aumasson, Willi Meier, Raphael Phan, Luca Henzen. «The Hash Function BLAKE» Архивная копия от 6 мая 2016 на Wayback Machine. 2014. p. 10.
- ↑ * M. Wegman and L. Carter, «New hash functions and their use in authentication and set equality», Journal of Computer and System Sciences, 22 (1981), pp. 265—279.
- ↑ Кнут, 2007, с. 508—513.
- ↑ M.0.RABIN,Probabilistic algorithms, in «Proceedings of Symposium on New Directions and Recent Results in Algorithms and Complexity» (J.F.Traub,Ed.), pp.21-39,Academic Press, New York, 1976.
- ↑ .GOTO AND Y.KANADA,Hashing lemmas on time complexities with applications to formula manipulation, in "Proceedings of the 1976 ACM Symposium on Symbolic and Algebraic Computation, " Yorktown Heights, N.Y.,pp.149—153.
- ↑ .GUSTAVSON AND D.Y.Y. YUN, Arithmetic complexity of unordered or sparse polynomials, in "Proceedings of the 1976 ACM Symposium on Symbolic and Algebraic Computation, " Yorktown Heights, N.Y.,pp.154—159.
Литература
- Cormen T. H., Leiserson C. E., Rivest R. L., Stein C. Алгоритмы: построение и анализ = Introduction to algorithms. — 2-е изд. — USA: MIT Press, 2001. — С. 234—237. — 1180 с. — ISBN 9780262032933.
- Дональд Кнут. Искусство программирования, том 3. Сортировка и поиск = The Art of Computer Programming, vol.3. Sorting and Searching. — 2-е изд. — М.: Вильямс, 2007. — С. 508—513, 557. — 824 с. — ISBN 0-201-89685-0.
- Michael Luby. Pseudorandomness and Cryptographic Applications. — USA: Princeton University Press, 1996. — С. 153—163. — 248 с. — ISBN 0691025460.