Самая быстрая хэш функция
Контейнеры на основе хэш-таблиц представляют собой очень быстрый ассоциативный массив (например unordered_map , unordered_set ).
Их производительность сильно зависит от хеш-функции, используемой для создания индекса для каждой записи. По мере роста хеш-таблиц элементы повторно хешируются снова и снова.
Указатели представляют собой простой тип, в основном это значение размером 4/8 байта, которое однозначно идентифицирует объект. Проблема в том, что использование адреса в результате хэш-функции неэффективно из-за того, что несколько младших битов равны нулю.
Более быстрая реализация - потерять несколько бит:
Последнее привело к увеличению производительности на 10-20% в большом приложении, использующем хеш-наборы и карты с десятками тысяч элементов, которые часто создаются и очищаются.
Может кто-нибудь предложить лучшую схему хеширования указателей?
Функция должна быть:
- Быстро! и должен быть хорошо встроен.
- Предлагайте разумное распределение, допускаются редкие коллизии.
Обновление - результаты тестов
Я провел два набора тестов: один для int* указателя класса, размер которого составляет 4 КБ, и для него. Результаты очень интересные.
Я использовал std::unordered_set для всех тестов размер данных 16 МБ, которые были выделены за один new вызов. Первый алгоритм запускался дважды, чтобы убедиться, что кеши максимально горячие, а ЦП работает на полной скорости.
Установка: VS2013 (x64), i7-2600, Windows 8.1 x64.
- VS2013 хэш-функция по умолчанию
- Хэш1: return (size_t)(val);
- Хэш2: return '(size_t)(val) >> 3;
- Hash3 (@BasileStarynkevitch): uintptr_t ad = (uintptr_t)val; return (size_t)((13 * ad) ^ (ad >> 15));
- Hash4 (@Roddy): uintptr_t ad = (uintptr_t)val; return (size_t)(ad ^ (ad >> 16));
- Hash5 (@egur):
- VS2013 по умолчанию занял 1292 мс
- Hash1 занял 742 мс
- Hash2 занял 343 мс
- Hash3 занял 1008 мс
- Hash4 занял 629 мс
- Hash5 занял 350 мс
Тест 1 - 4K_class* :
- VS2013 по умолчанию занял 0,423 мс
- Hash1 занял 23,889 мс
- Hash2 занял 6,331 мс
- Hash3 занял 0,366 мс
- Hash4 занял 0,390 мс
- Hash5 занял 0,290 мс
Обновление2:
Пока что победителем является шаблонная хеш-функция (Hash5). Лучший уровень производительности по скорости для блоков различного размера.
Обновление 3: добавлена хеш-функция по умолчанию для базовой линии. Оказывается, это далеко не оптимально.
Этот сдвиг зависит от соотношения вашего T , как в unordered_set
@MaximYegorushkin, int это не указатель. 32-битные указатели, возвращаемые malloc / new имеют 1 нулевой LSB, а 64-битные имеют 3 нулевых LSB. Конечно, у вас могут быть указатели, которые не являются результатом malloc / new , поэтому вы получите несколько столкновений, если объекты достаточно малы.
Простите, я действительно имел в виду unordered_set . Эти int s могут быть сохранены в массиве в другом месте, так что, естественно, int* будет только 2 нулевых LSB как на 32-битных, так и на 64-битных платформах.
Отличается ли тестовый код принципиально для Test 1 от Test2? Разница в 1000 раз в самых быстрых таймингах . Но интересно!
Поскольку размер блока в 1000 раз больше, я использовал меньше блоков. Число будет постоянным (+ -2%), если я использую больше блоков.
Правильный ответ с теоретической точки зрения: «Используйте std::hash специализированное использование настолько хорошо, насколько это возможно, и если это не применимо, используйте хорошую хеш-функцию, а не быструю. Скорость хеш-функции делает не так важно, как его качество » .
Практический ответ: «Использование std::hash , что моча бедных, но тем не менее выполняет удивительно хорошо.»
TL; DR.
Заинтриговавшись, я провел около 30 часов тестов за выходные. Среди прочего, я попытался получить средний случай по сравнению с наихудшим случаем и попытался принудить std::unordered_map к наихудшему поведению, дав ему заведомо неверные подсказки о количестве сегментов в отношении вставленного установленного размера.
Я сравнил плохие хеши ( std::hash ) с хорошо известными хешами общего назначения общего хорошего качества (djb2, sdbm), а также их вариациями, которые учитывают очень короткую длину ввода, и с хэшами, которые явно используются в хэш-таблицах ( murmur2 и murmur3), и хэши с низким содержанием мочи, которые на самом деле хуже, чем полное отсутствие хеширования, поскольку они отбрасывают энтропию.
Поскольку младшие 2–3 бита всегда равны нулю на указателях из-за выравнивания, я счел целесообразным протестировать простой сдвиг вправо как «хэш», поэтому будет использоваться только ненулевая информация, в случае, если хеш-таблица, например, используется только самые младшие N бит. Оказалось, что для разумных сдвигов (я также пробовал необоснованные сдвиги!) Это действительно работает довольно хорошо.
Скоростное хеширование на базе нового криптографического алгоритма
К сожалению, математики слабо разбираются в тонкостях программирования, они что-то выдумывают, а потом программист должен это реализовать в программном коде. Далеко не всегда возможно реализовать их алгоритмы эффективно.
Особенно явно это проявляется в Российской симметричной криптографии последнего времени, «Стриборг» и «Кузнечик»… Эти алгоритмы реализовать эффективно в программных кодах х86/64 невозможно, нужен специализированный криптопроцессор.
Сделаем все наоборот и посмотрим, что получится.
Программист, знающий как работает современный процессор х86/64, займется разработкой максимально эффективного алгоритма симметричного шифрования, а математики, как в старые добрые времена, пускай занимаются своей основной работой,- криптоанализом получившегося решения.
Помня, что «Лучшее-враг хорошему», возьмем за основу «хорошее» — ГОСТ 28147-89. Затем по врачебному принципу «Не навреди» усилим его методами многопоточных вычислений.
Было сделано следующее:
- Увеличен размер ключа до 256байт.
- Увеличен размер блока данных до 256байт.
- Операция подстановки заменена операцией перестановки.
- В циклическом сдвиге внедрена операция инвертирования групп бит.
- Ввод ключей выполнен в виде перестановки бит.
- Сеть Фейстеля модифицирована в кольцевую сеть из восьми сегментов.
- Используется режим гаммирования с обратной связью, в два прохода по шифруемым данным.
- Проходы производятся с разными перестановками и кольцевыми сдвигами он с одинаковыми ключами.
- Перед шифрацией из шифруемого текста удаляется избыточность с помощью компрессора.
13 Answers 13
And the code used to generate this is:
Thank you for your code. I have improved it a little bit. I don't think that we should compare functions like md5() that process the whole string and loops that do byte by byte like you made with xor. In PHP, these loops are very slow and are even slower than the md5 itself. We should compare one hases with another, all implemented as functions.
Just a quick note - I tried this with a much longer string (~5000 chars) and CRC32 was slower than MD5 and SHA1 on my machine (i7-6650U, 16GB). CRC32 - 1.7s , MD5 - 1.4s, SHA1 - 1.5s. Always test for yourself.
@Quamis the test is nice but may be misleading - as @samTolton noted the results are different and md5 is faster. A better test will be to randomize the strings content and length too. this way we get a better idea about the actual real world performance. This will also avoid caching. Take a look: php hashing checksum performance
There's a speed comparison on the xxHash repository. This is what it shows, on January 12, 2021.
Hash Name | Width | Bandwidth (GB/s) | Small Data Velocity | Quality | Comment |
---|---|---|---|---|---|
XXH3 (SSE2) | 64 | 31.5 GB/s | 133.1 | 10 | |
XXH128 (SSE2) | 128 | 29.6 GB/s | 118.1 | 10 | |
RAM sequential read | N/A | 28.0 GB/s | N/A | N/A | for reference |
City64 | 64 | 22.0 GB/s | 76.6 | 10 | |
T1ha2 | 64 | 22.0 GB/s | 99.0 | 9 | Slightly worse [collisions] |
City128 | 128 | 21.7 GB/s | 57.7 | 10 | |
XXH64 | 64 | 19.4 GB/s | 71.0 | 10 | |
SpookyHash | 64 | 19.3 GB/s | 53.2 | 10 | |
Mum | 64 | 18.0 GB/s | 67.0 | 9 | Slightly worse [collisions] |
XXH32 | 32 | 9.7 GB/s | 71.9 | 10 | |
City32 | 32 | 9.1 GB/s | 66.0 | 10 | |
Murmur3 | 32 | 3.9 GB/s | 56.1 | 10 | |
SipHash | 64 | 3.0 GB/s | 43.2 | 10 | |
FNV64 | 64 | 1.2 GB/s | 62.7 | 5 | Poor avalanche properties |
Blake2 | 256 | 1.1 GB/s | 5.1 | 10 | Cryptographic |
SHA1 | 160 | 0.8 GB/s | 5.6 | 10 | Cryptographic but broken |
MD5 | 128 | 0.6 GB/s | 7.8 | 10 | Cryptographic but broken |
It seems xxHash is by far the fastest one, while many others beat older hashes, like CRC32, MD5 and SHA.
But you should be aware that CRC32 will have more collisions than MD5 or even SHA-1 hashes, simply because of the reduced length (32 bits compared to 128 bits respectively 160 bits). But if you just want to check whether a stored string is corrupted, you'll be fine with CRC32.
Wow, only required datatype is an unsigned integer, this will be SIGNIFICANLY faster than other hashing.
@John: or not. CRC32 turns out to be slower than MD4, and not much faster than MD5, on ARM processors. Besides, CRC32 uses an unsigned 32-bit integer type, which is exactly all that MD5 needs.
Ranked list where each loop shares the same thing to crypt as all the others.
There's a minimal off-by-one error at the end. strlen($characters) should be strlen($characters) - 1 :)
2019 update: This answer is the most up to date. Libraries to support murmur are largely available for all languages.
The current recommendation is to use the Murmur Hash Family (see specifically the murmur2 or murmur3 variants).
Murmur hashes were designed for fast hashing with minimal collisions (much faster than CRC, MDx and SHAx). It's perfect to look for duplicates and very appropriate for HashTable indexes.
In fact it's used by many of the modern databases (Redis, ElastisSearch, Cassandra) to compute all sort of hashes for various purposes. This specific algorithm was the root source of many performance improvements in the current decade.
It's also used in implementations of Bloom Filters. You should be aware that if you're searching for "fast hashes", you're probably facing a typical problem that is solved by Bloom filters. ;-)
Note: murmur is a general purpose hash, meaning NON cryptographic. It doesn't prevent to find the source "text" that generated a hash. It's NOT appropriate to hash passwords.
It seems that crc32 is faster for small messages(in this case 26 characters) while md5 for longer messages(in this case >852 characters).
Instead of assuming that MD5 is "fairly slow", try it. A simple C-based implementation of MD5 on a simple PC (mine, a 2.4 GHz Core2, using a single core) can hash 6 millions of small messages per second. A small message is here anything up to 55 bytes. For longer messages, MD5 hashing speed is linear with the message size, i.e. it crunches data at about 400 megabytes per second. You may note that this is four times the maximum speed of a good harddisk or a gigabit ethernet network card.
Since my PC has four cores, this means that hashing data as fast as my harddisk can provide or receive uses at most 6% of the available computing power. It takes a very special situation for hashing speed to become a bottleneck or even to induce a noticeable cost on a PC.
On much smaller architectures where hashing speed may become somewhat relevant, you may want to use MD4. MD4 is fine for non-cryptographic purposes (and for cryptographic purposes, you should not be using MD5 anyway). It has been reported that MD4 is even faster than CRC32 on ARM-based platforms.
По сути, я готовлю фразы для ввода в базу данных, они могут быть искажены, поэтому вместо этого я хочу сохранить их короткий хеш (я просто буду сравнивать, существуют они или нет, поэтому хеш-код идеален).
Я предполагаю, что MD5 довольно медленно обрабатывает более 100000 запросов, поэтому я хотел знать, какой метод является лучшим для хеширования фраз, может быть, развернуть мою собственную хеш-функцию или hash('md4', '. ' в конце концов ее использование будет быстрее?
Я знаю, что MySQL имеет MD5 (), так что это немного повысит скорость выполнения запроса, но, возможно, в MySQL есть более быстрая функция хеширования, о которой я не знаю, которая будет работать с PHP ..
Это очень хороший вопрос, и комментарии, подразумевающие, что это не так или неважно, и / или должны быть очевидными и / или интуитивно понятными, разочаровывают и разочаровывают. (И тоже совсем не неожиданно.)
И код, используемый для его создания:
Ах, спасибо за это понимание, на самом деле, просто укрепляет мое использование CRC32 как самого быстрого.
Спасибо за ваш код. Я его немного улучшил. Я не думаю, что мы должны сравнивать такие функции, как md5 (), которые обрабатывают всю строку, и циклы, которые делают побайтно, как вы сделали с xor. В PHP эти циклы очень медленные и даже медленнее, чем сам md5. Мы должны сравнивать одни хаки с другими, все они реализованы в виде функций.
Просто небольшое примечание - я пробовал это с гораздо более длинной строкой (~ 5000 символов), и CRC32 был медленнее, чем MD5 и SHA1 на моей машине (i7-6650U, 16 ГБ). CRC32 - 1,7 с, MD5 - 1,4 с, SHA1 - 1,5 с. Всегда проверяйте на себе.
@Quamis тест хорош, но может вводить в заблуждение - как заметил @samTolton, результаты другие и md5 быстрее. Лучшим тестом будет также рандомизация содержимого и длины строк. таким образом мы получаем лучшее представление о реальной производительности в реальном мире. Это также позволит избежать кеширования. Взгляните: производительность контрольной суммы хеширования php
Но вы должны знать, что CRC32 будет иметь больше коллизий, чем хэши MD5 или даже SHA-1, просто из-за уменьшенной длины (32 бита по сравнению со 128 битами, соответственно, 160 бит). Но если вы просто хотите проверить, не повреждена ли сохраненная строка, вам подойдет CRC32.
Вау, только требуемый тип данных - это целое число без знака, это будет ЗНАЧИТЕЛЬНО быстрее, чем другое хеширование.
@ Джон: или нет. CRC32 оказывается медленнее, чем MD4, и ненамного быстрее, чем MD5 на процессорах ARM. Кроме того, CRC32 использует беззнаковый 32-битный целочисленный тип, а это как раз все, что нужно MD5 .
Ранжированный список, в котором каждый цикл использует то же самое, что и все остальные.
В конце есть минимальная ошибка с разницей в единицу. strlen($characters) должно быть strlen($characters) - 1 :)
В репозитории xxHash есть сравнение скорости . Это то, что он показывает 12 января 2021 года.
Имя хэша | Ширина | Пропускная способность (ГБ / с) | Малая скорость передачи данных | Качественный | Комментарий |
---|---|---|---|---|---|
XXH3 (SSE2) | 64 | 31,5 ГБ / с | 133,1 | 10 | |
XXH128 (SSE2) | 128 | 29,6 ГБ / с | 118,1 | 10 | |
Последовательное чтение RAM | N / A | 28,0 ГБ / с | N / A | N / A | для справки |
Город64 | 64 | 22,0 ГБ / с | 76,6 | 10 | |
T1ha2 | 64 | 22,0 ГБ / с | 99,0 | 9 | Чуть хуже [столкновения] |
Город128 | 128 | 21,7 ГБ / с | 57,7 | 10 | |
XXH64 | 64 | 19,4 ГБ / с | 71,0 | 10 | |
SpookyHash | 64 | 19,3 ГБ / с | 53,2 | 10 | |
Мама | 64 | 18,0 ГБ / с | 67,0 | 9 | Чуть хуже [столкновения] |
XXH32 | 32 | 9,7 ГБ / с | 71,9 | 10 | |
Город32 | 32 | 9,1 ГБ / с | 66,0 | 10 | |
Мурмур3 | 32 | 3,9 ГБ / с | 56,1 | 10 | |
SipHash | 64 | 3,0 ГБ / с | 43,2 | 10 | |
FNV64 | 64 | 1,2 ГБ / с | 62,7 | 5 | Плохие лавинные свойства |
Blake2 | 256 | 1,1 ГБ / с | 5.1 | 10 | Криптографический |
SHA1 | 160 | 0,8 ГБ / с | 5,6 | 10 | Криптографический, но сломанный |
MD5 | 128 | 0,6 ГБ / с | 7,8 | 10 | Криптографический, но сломанный |
Кажется, что xxHash на сегодняшний день является самым быстрым, в то время как многие другие бьют старые хеши, такие как CRC32, MD5 и SHA.
Обновление 2019: этот ответ самый последний. Библиотеки для поддержки ропота в основном доступны для всех языков.
Текущая рекомендация заключается в использовании семейства Murmur Hash (см., В частности, варианты murmur2 или murmur3 ).
Хеши Murmur были разработаны для быстрого хеширования с минимальными коллизиями (намного быстрее, чем CRC, MDx и SHAx). Он идеально подходит для поиска дубликатов и очень подходит для индексов HashTable.
Фактически, он используется многими современными базами данных (Redis, ElastisSearch, Cassandra) для вычисления всевозможных хэшей для различных целей. Этот конкретный алгоритм стал основным источником многих улучшений производительности в текущем десятилетии.
Он также используется в реализациях фильтров Блума . Вы должны знать, что если вы ищете «быстрые хэши», вы, вероятно, столкнетесь с типичной проблемой, которую решают фильтры Блума. ;-)
Примечание : murmur - это хеш общего назначения, что означает НЕ криптографический. Это не мешает найти исходный «текст», сгенерировавший хеш. Это НЕ подходит для хеширования паролей.
Существует открытый запрос здесь , чтобы добавить murmurhash на PHP, который вы можете проголосовать.
Поскольку мой компьютер имеет четыре ядра, это означает, что хеширование данных с той скоростью, с которой мой жесткий диск может предоставлять или получать, использует не более 6% доступной вычислительной мощности. Требуется особая ситуация, чтобы скорость хеширования стала узким местом или даже вызвала заметные затраты на ПК.
На гораздо меньших архитектурах, где скорость хеширования может стать актуальной, вы можете использовать MD4. MD4 подходит для некриптографических целей (и для криптографических целей вы в любом случае не должны использовать MD5). Сообщалось, что MD4 даже быстрее, чем CRC32 на платформах на базе ARM.
Есть повод задуматься. MD5 занимает 128 бит вместо 32. Это означает, что хранилище базы данных занимает в 4 раза больше места и, следовательно, в 4 раза медленнее искать для сравнения хэши (я думаю ). Что меня беспокоит (для моих целей), так это то, насколько быстро будет выполняться запрос к базе данных позже, когда она будет заполнена хешами.
Если вы не используете достаточно широкий вывод, вы получите случайные коллизии, что будет плохо, поскольку цель состоит в том, чтобы запросить базу данных, чтобы узнать, известна ли данная «фраза»; коллизии здесь превращаются в ложные срабатывания. С 32 битами вы начнете видеть коллизии, как только у вас будет 60000 или около того фраз. Это верно для всех хэш-функций, криптографических или нет. При этом вы всегда можете взять результат хэш-функции и усечь его до любой длины, которую сочтете нужной, в рамках ограничений, описанных выше.
@ThomasPornin Если мы пойдем путем усечения, не будет ли он снова столкнуться с проблемой столкновения, я имею в виду, что единственная причина, по которой md5 не должен получать легкое столкновение, - это лишнее количество символов, которые у него есть по сравнению с CRC32, верно?
Если вас беспокоит, сколько места требуется для хэша в базе данных, вполне допустимо использовать только первые X бит хэша. Не обязательно рекомендовать это, но вы можете использовать MD5 и использовать только первые четыре байта.
Предостережение
Приведенный ниже ответ не отвечает на заданный вопрос, поскольку не рекомендует хэш-функции. Помните: «Хеш-функция - это любая функция, которая может использоваться для отображения данных произвольного размера в значения фиксированного размера». (Википедия) В приведенном ниже ответе рекомендуются преобразования, которые не гарантируют результатов фиксированного размера.
Если вы хотите ослабить требование использования хеш-функции , читайте дальше .
Оригинальный ответ
Я предлагаю urlencode () или base64_encode () по следующим причинам:
- Вам не нужна криптография
- Вы хотите скорости
- Вам нужен способ идентифицировать уникальные строки при очистке `` искаженных '' строк
Практическая реализация РУ2
Алгоритм «Русская рулетка» встроен в криминалистический дубликатор HDD и SDD дисков. Алгоритм используется там для создания дифференциальных бэкапов, контроля целостности, ограничения доступа на основе пароля и сжатия информации.
О компрессоре для удаления избыточности уже писалось ранее в статье «Новый алгоритм скоростной компрессии данных», хеширование используется для подтверждения целостности скопированных данных, а в случае ввода пароля еще и для «парольной защиты» полученных дампов от просмотра/модификации.
Вот скоростные характеристики РУ2 полученные в реальной работе по созданию дифференциального бэкапа:
Скорость копирования ограничена параметрами устройства чтения, большую скорость чтения SSD диск подключенный через мост USB 3.0-SATA обеспечить не может.
На скорости входного потока 360МегаБайт/сек. алгоритм РУ2 грузит процессор всего на 5% при сниженной частоте работы 1.4ГигаГерца. При этом обеспечивается сжатие информации, ее хеширование и шифрация (парольная защита) дампа.
Традиционные системы хеширования такую производительность обеспечить не могут. Для сравнения, вот как работает система хеширования встроенная в «Акронис» при создании дифференциального бэкапа того же диска:
Процессор хеширует входной поток данных со скоростью 340МегаБайт/сек., работает при этом на частоте 3.8ГигаГерца и загружен на 28%.
Если пересчитать полученные результаты в предельные параметры для двухядерного процессора работающего на частоте 3.8ГигаГерца, то система хеширования «Акрониса» может обеспечить пропускную способность в 1.4ГигаБайт/сек.
Гораздо более загруженный задачами (хеширование+сжатие+«парольная защита») алгоритм «Русской Рулетки» обеспечивает скорость 21ГигаБайт/сек.
Другими словами, хеширование РУ2 работает на порядок быстрее чем стандартное хеширование реализованное в «Акронисе».
Кроме того, «Русская Рулетка» обеспечивает скорость генерации псевдослучайных чисел на уровне 12 ГигаБайт в секунду. Это самый скоростной генератор псевдослучайных последовательностей из известных, удовлетворяющий требованиям официальных тестов NIST.
Генерация случайных чисел, хеширование, парольная защита, пока этого для «Русской Рулетки» хватит.
I'm essentially preparing phrases to be put into the database, they may be malformed so I want to store a short hash of them instead (I will be simply comparing if they exist or not, so hash is ideal).
I assume MD5 is fairly slow on 100,000+ requests so I wanted to know what would be the best method to hash the phrases, maybe rolling out my own hash function or using hash('md4', '. ' would be faster in the end?
I know MySQL has MD5(), so that would complement a bit of speed on the query end, but maybe there's further a faster hashing function in MySQL I don't know about that would work with PHP..
NullUserException: You're right, I'll try them with random length phrases. Just wanted insight on what would be the norm if any to handle this sort of thing.
This is a very good question to ask, and the comments implying it isn't, or is unimportant, and/or should be obvious and/or intuitive -- are disappointing & frustrating. (And also not at all unexpected.)
Тестовая реализация
Алгоритм реализован, и первое что тестируется, это его статистические параметры при генерации псевдослучайной последовательности (компрессор отключен), вот как они выглядит:
Это типичный результат тестов NIST нового криптопреобразования. Результаты тестов на любых случайных ключах и первоначальных заполнениях всегда укладываются в статистические параметры случайной последовательности.
Полученные в экспериментах по нормам 8 байтного блочного шифра статистические параметры для блочного шифра с размером блока 256 байт это фантастика.
Это все равно что, к примеру, подбросив монетку 12 раз и получив равное выпадение «орла» и «орешки», требовать, чтобы кубик, тоже брошенный 12 раз, выпал на каждую грань обязательно по два раза…
Такое теоретически возможно только при очень высокой дифференциальной энтропии между смежными блоками и характеризует уровень сложности блочного шифра.
Эти параметры гаммы получены при одном раунде преобразования. Алгоритм имеет особенность,- скорость гаммирования зависит от производительности оперативной памяти и кеша, а не от быстродействия процессора.
Выводы
Некоторые из моих открытий были хорошо известны и неудивительны, другие очень удивительны:
Испытательная установка
Тесты проводились для наборов из 50000 и 1000000 объектов размером 4, 16, 64, 256 и 1024 (результаты для 64 здесь опущены для краткости, они, как и следовало ожидать, находятся где-то посередине между 16 и 256 - StackOverflow позволяет размещать только 30 тыс. символов).
Набор тестов был выполнен 3 раза, результаты менялись на 3 или 4 миллисекунды, но в целом идентичны. Опубликованные здесь результаты являются последним запуском.
Порядок вставок в «случайном» тесте, а также шаблон доступа (в каждом тесте) псевдослучайны, но точно идентичны для каждой хеш-функции в тестовом прогоне.
Тайминги для хеш-тестов предназначены для суммирования 4 000 000 000 хеш-значений в целочисленной переменной.
Столбец insert - это время в миллисекундах для 50 итераций создания std::unordered_map , вставки 50 000 и 1 000 000 элементов соответственно и уничтожения карты.
Столбец access - это время в миллисекундах для выполнения 100000000 поисков псевдослучайного элемента в «векторе» с последующим поиском этого адреса в unordered_map .
Это время включает в среднем один промах кеша для доступа к случайному элементу в vector , по крайней мере, для большого набора данных (небольшой набор данных полностью помещается в L2).
Все тайминги на Intel Core2 2,66 ГГц, Windows 7, gcc 4.8.1 / MinGW-w64_32. Детализация таймера @ 1 мс.
Исходный код
Исходный код доступен на Ideone , опять же из-за ограничения Stackoverflow в 30 тыс. Символов.
Примечание. Выполнение полного набора тестов на настольном ПК занимает более 2 часов, поэтому будьте готовы прогуляться, если хотите воспроизвести результаты.
Бенчмарки сделаны в программе SMHasher на Core 2 Duo 3,0 ГГц
На Хабре неоднократно рассказывали про некриптографические хеш-функции, которые на порядок быстрее криптографических. Они применяются там, где важна скорость и нет смысла применять медленные MD5 или SHA1. Например, для построения хеш-таблиц с хранением пар ключ-значение или для быстрой проверки контрольной суммы при передаче больших файлов.
Одно из самых популярных — семейство хеш-функций xxHash, которое появилось около пяти лет назад. Хотя изначально эти хеши задумывались для проверки контрольной суммы при сжатии LZ4, но их стали применять на самых разных задачах. Оно и понятно: достаточно посмотреть на таблицу вверху со сравнением производительности xxHash и некоторых других хеш-функций. В этом тесте xxHash обходит ближайшего конкурента по производительности в два раза. Новая версия XXH3 поднимает планку ещё выше.
Здесь и далее диаграммы кликабельны
В XXH3 внутренний цикл, который оптимально обрабатывается векторизацией. Благодаря этому функция использует аппаратную поддержку на наборах инструкций SSE2, AVX2 и NEON. Производительность зависит от комилятора. Неожиданно оказалось, что версия, скомпилированная clang, намного превосходит остальные. Ян Колле даже подумал, что производительность хеш-функции здесь превысит пропускную способность памяти. Этой версии на графике соответствует пунктирная линия.
В итоге оказалось, что у хеш-функции с поддержкой AVX2 пропускная способность гораздо выше, чем у оперативной памяти, так что важным фактором становится объём кэша. Впрочем, во многих задачах приходится обрабатывать данные, которые уже находятся в кэше, так что работа со скоростью быстрее памяти вполне имеет смысл.
Поддержка инструкций SSE2 позволяет новой хеш-функции значительно обойти XXH32 на 32-битных приложениях, которые по-прежнему часто встречаются в реальном мире (например, байткод WASM).
На маленьких входных данных (20-30 байт) хеш-функция XXH3 ненамного, но всё-таки превосходит CityHash от Google, а также FarmHash, которые раньше были явными лидерами.
На следующем графике приведены результаты самого реалистичного теста с входными данными переменной длины (случайная величина от 1 до N).
В ещё одном тесте учитывается задержка: здесь хеширование начинается по сигналу. Идея в том, чтобы симулировать реальную рабочую нагрузку, где хеш-функция не работает непрерывно, а вызывается в другими процессами в определённый момент.
Автор пишет, что данный тест с умножением 64×64=>128 бит отдаёт предпочтение алгоритмам mumv2 от Владимира Макарова и t1ha2 от Лео Юрьева.
Наконец, вот итоговый и самый важный график, который показывает скорость хеширования на входных данных переменной длины с учётом задержки. Он отражает реальное применение хеш-функции, например, в базах данных.
XXH3 вышла в составе пакета xxHash v0.7.0. У неё стоит пометка «экспериментальная», а для разлочки нужно применить макрос XXH_STATIC_LINKING_ONLY . Автор поясняет, что хеш-функцию пока можно использовать только на тестовых эфемерных данных, но не для реального сохранения хешей. По итогам экспериментального периода и сбора отзывов пользователей функция XXH3 получит стабильный статус в следующей версии xxHash.
Русская Рулетка, 2018 и его применение
В последнее время криптографические алгоритмы у нас стали получать звучные названия, типа «Магма», «Кузнечик», «Стрибог», продолжим эту традицию.
Будем называть этот блочный шифр «Русская рулетка» или сокращенно РУ2, в честь первого чисто русского генератора случайных бинарных последовательностей,- вращающегося барабана револьвера…
Ну и кроме того, криптопреобразование построено на вращениях (кольцевых сдвигах) бинарных последовательностей. Таких сдвигов там только в явном виде 192 штуки за один раунд.
Так что прямая аналогия с барабаном револьвера очевидна.
Ранее, при внедрении параллельного метода реализации ГОСТ 28147-89 на XMM/YMM регистрах пришлось его полностью описать, поскольку он проходил официальную сертификацию ФСБ.
Сейчас ситуация другая, никакого официоза не предполагается. Поэтому подробного описания алгоритма «Русская рулетка» не будет, это своеобразная копирайт защита. Короче говоря, алгоритм «Русской Рулетки» пока будет проприетарным и соответственно его полное обозначение Русская Рулетка, 2018 или сокращенно РУ2.
Закрытый от исследования алгоритм шифрования,- это конечно нонсенс, поскольку отсутствует доверие к надежности шифрования.
Но ничто не мешает использовать алгоритм РУ2 для конвертации шифруемого текста в последовательность удовлетворяющей требованиям псевдослучайности.
Затем полученную псевдослучайную последовательность можно шифровать известными и «надежными» алгоритмами, собственно так и построены все серьезные криптографические систем.
Пока же «Русская Рулетка» используется для скоростного хеширования с произвольным размером результата хеш-функции. Это важно в задачах резервного копирования и контроля целостности.
Стандартное гаммирование с обратной связью превращается в Хэш-функцию если провести второй проход по зашифрованным данным. Именно так изначально реализован алгоритм РУ2.
Двойное гаммирование с обратной связью не рассматривалось ранее как вариант реализации хеш-функции видимо из-за низкой скорости работы, хотя обладает более надежными параметрами свертки. Это касается в первую очередь лавинного эффекта, он действует не только на последующие раунды свертки, но и на предыдущие.
Причем полученные характеристики хэш-функции надежно проверяются статистическими тестами, ведь весь полученный шифротекст, являющийся надежной псевдослучайной гаммой, становится хэшем.
Из этой гаммы можно вырезать произвольные куски для хранения значения хэш-функции. Сейчас используется блок размером 1024Байт, это гораздо надежнее чем блок из 64Байт в самом «продвинутом» стандарте SHA3-512.
Хеширование РУ2 защищает данные от просмотра/модификации, но пока криптографы не убедились в стойкости алгоритма будем его считать парольной защитой данных для ограничения доступа.
Читайте также: