Ищем хороший 64-битный хеш для путей к файлам в UTF16

У меня путь в кодировке Unicode / UTF-16. разделитель путей - U + 005C '\'. Пути представляют собой корневые относительные пути файловой системы Windows с завершающим нулем, например "\ windows \ system32 \ drivers \ myDriver32.sys"

Я хочу преобразовать этот путь в 64-битное целое число без знака. Он не обязательно должен быть "криптографически надежным". Хэши должны быть нечувствительны к регистру, но способны обрабатывать буквы, отличные от ascii. Очевидно, что хеш тоже должен хорошо разлетаться.

У меня возникло несколько идей:

A) Использование идентификатора файла Windows в качестве «хеша». В моем случае я хочу, чтобы хеш изменялся при перемещении файла, так что это не вариант.

Б) Просто используйте обычный хеш-код: hash + = prime * hash + codepoint для всей строки.

У меня есть ощущение, что тот факт, что путь состоит из «сегментов» (имена папок и окончательное имя файла), можно использовать.

Подводя итог потребностям:

1) 64-битный хэш
2) хорошее распределение / небольшое количество конфликтов для путей файловой системы.
3) эффективный
4) не требует защиты
5) нечувствителен к регистру


person Dominik Weber    schedule 15.09.2010    source источник
comment
Приведенные ниже ответы адекватны, но я надеялся получить хэш, который использует тот факт, что ввод представляет собой путь к файлу utf-16.   -  person Dominik Weber    schedule 18.09.2010
comment
Для криптографических хэшей практически не имеет значения, является ли это UTF-16 или любая другая кодировка, потому что они спроектированы непредсказуемыми и используют всю информацию, предоставленную вводом в каждый бит результирующего хэша для идеального распределения с минимальной коллизией (по крайней мере, теоретически - чем более безопасен хеш, тем больше считается, что он удовлетворяет этому), поэтому вы можете использовать любая часть этого хеша.   -  person Arc    schedule 18.09.2010
comment
но есть пробелы в кодовом пространстве UTF-16, которое используется частным образом, и символы верхнего или нижнего регистра не используются. Или бесполезно беспокоиться о структуре входных данных?   -  person Dominik Weber    schedule 20.09.2010
comment
Теоретически это не должно иметь значения для хорошей крипто-хеш-функции. Конечно, вероятно, есть скрытые зависимости от структуры хешированных данных, но они вряд ли должны быть заметны для вашего приложения, так как в противном случае я предполагаю, что кто-то обнаружил бы это при изучении хеш-функций, и это, вероятно, сразу же убило бы хеш для использования в криптовалюте. Считается, что безопасные хэши - лучшее, что вы можете получить для идеального распространения.   -  person Arc    schedule 21.09.2010
comment
На следующей странице представлено несколько эффективных реализаций хэш-функций общего назначения, которые демонстрируют минимальные коллизии: partow .net / programming / hashfunctions / index.html   -  person    schedule 01.01.2011


Ответы (4)


Криптографически безопасные хэши могут быть не очень эффективными с точки зрения скорости, но существуют реализации, доступные практически для любого языка программирования.
Возможность их использования для вашего приложения зависит от того, насколько вы зависите от скорости, которую эталонный тест даст вам подходящую ответ на это.

Вы можете использовать подстроку такого хэша, например MD5 на вашем пути, ранее преобразованный в нижний регистр, так что хеш фактически нечувствителен к регистру (требуется, чтобы вы использовали метод для нижнего регистра, который знает, как преобразовать все нестандартные символы UTF-16, которые могут встречаться в файловой системе ).

Криптографически безопасные хэши имеют преимущество довольно равномерного распределения независимо от того, какую часть подстроки вы выберете, потому что они спроектированы так, чтобы быть непредсказуемыми, то есть каждая часть хэша в идеале зависит от всех хешированных данных, как и любая другая их часть.

person Arc    schedule 15.09.2010
comment
Спасибо, но MD5 и почти любой другой известный мне криптографический хеш больше 64 бит. Для этого мне пришлось бы свернуть ключевое пространство. У меня есть метод Unicode 5.1, основанный на строчных строках, который довольно быстр. - person Dominik Weber; 16.09.2010
comment
Да, как я уже сказал, тогда вам нужно будет взять 64-битную подстроку MD5. В качестве альтернативы взгляните на этот вопрос: stackoverflow.com/questions/1660501/ - person Arc; 16.09.2010
comment
Да, это сработает - я был сбит с толку подстингом - я подумал, что это относится к пути к файлу, а не к полученному хешу. - person Dominik Weber; 18.09.2010
comment
Выбрал это, потому что это кажется мне лучшим решением и хорошим продолжением в комментариях! Спасибо! - person Dominik Weber; 24.09.2010

Я бы просто использовал что-нибудь прямолинейное. Я не знаю, какой язык вы используете, поэтому это псевдокод:

ui64 res = 10000019;
for(i = 0; i < len; i += 2)
{
  ui64 merge = ucase(path[i]) * 65536 + ucase(path[i + 1]);
  res = res * 8191 + merge; // unchecked arithmetic
}
return res;

Я предполагаю, что path[i + 1] безопасно на том основании, что если len нечетно, то в последнем случае он безопасно прочитает U + 0000.

Я бы не стал использовать тот факт, что есть пробелы, вызванные пробелами в UTF-16, строчными и заглавными символами, а также символами, недопустимыми для путей, потому что они не распределены таким образом, чтобы использовать об этом факте можно было бы быстро использовать. Уменьшение на 32 (все символы ниже U + 0032 недопустимы в именах путей) было бы не слишком дорого, но и не слишком улучшило бы хеширование.

person Jon Hanna    schedule 22.09.2010
comment
Это неплохо - это позволяет избежать использования всей строки с заглавной буквы - и уловка с завершением нуля удобна. - person Dominik Weber; 23.09.2010
comment
Ну, по сути, он использует всю строку в бите UCase с большой буквы. Этот фрагмент псевдокода предназначен для обозначения заглавных букв. Независимо от того, выполняется ли это как строка или символ за символом (в том числе как эффективность), если я правильно помню, что сворачивание корпуса файла является символом за символом и не зависит от культуры. Я мог ошибаться в этом воспоминании. В любом случае вы захотите использовать тот же метод, что и Windows File sys. - person Jon Hanna; 23.09.2010

Даже если вам не нужен криптографический хеш, вы все равно можете его использовать, а поскольку ваша проблема не в безопасности, то «сломанный» криптографический хеш вполне подойдет. Я предлагаю MD4, что довольно быстро. На моем ПК (система Core2 с частотой 2,4 ГГц, использующая одно ядро) MD4 хэширует более 700 МБ / с, и даже для небольших входных данных (менее 50 байт) он может обрабатывать около 8 миллионов сообщений в секунду. Вы можете найти более быстрые некриптографические хэши, но для того, чтобы ощутить заметную разницу, уже требуется довольно специфическая ситуация.

Для конкретных свойств, которые вам нужны, вам понадобятся:

  1. Для «нормализации» символов так, чтобы прописные буквы преобразовывались в строчные (для нечувствительности к регистру). Обратите внимание, что, вообще говоря, нечувствительность к регистру в мире Unicode - непростая задача. Из того, что вы объясняете, я понимаю, что вам нужна только такая же нечувствительность к регистру, которую Windows использует для доступа к файлам (я думаю, что это только ASCII, поэтому преобразование верхнего регистра-> нижнего регистра выполняется просто ).

  2. Чтобы усечь вывод MD4. MD4 выдает 128 бит; просто используйте первые 64 бита. Это будет настолько разбросано, насколько вы можете пожелать.

Реализации MD4 доступны в некоторых местах, в том числе прямо в RFC 1320, ссылка на который приведена выше. Вы также можете найти реализации MD4 с открытым исходным кодом на C и Java в sphlib.

person Thomas Pornin    schedule 16.09.2010
comment
Да, крипто-хеши сами по себе не должны быть плохими, поэтому при необходимости я предлагаю провести несколько тестов для оценки. Поддержка MD4 может быть прекращена для некоторых крипто-библиотек, поскольку она считается небезопасной, поэтому широко внедренный MD5 может быть более перспективным в отношении переносимости и совместимости. Насколько мне известно, Windows поддерживает имена файловых систем Unicode для NTFS и VFAT (UTF-16; согласно Википедии, NTFS использует 16-битные символы, которые могут, но не обязательно, быть UTF-16). en.wikipedia.org/wiki/NTFS - person Arc; 17.09.2010
comment
фактически каждый том NTFS имеет карту верхнего регистра, которую драйвер файловой системы использует для сравнения без учета регистра. - person Dominik Weber; 17.09.2010
comment
Что касается скорости, хэш-код, используемый Java в этом связанном вопросе, на который я ссылался, может быть достаточно хорошим также для скомпилированных языков (включая C / C ++ и Java) - для динамически интерпретируемых языков (например, PHP , Perl), хеш-функция, предоставляемая библиотекой функций языка (которая обычно находится в машинном коде), может быть быстрее, чем функция, которую вы предоставляете на интерпретируемом языке (также зависит от длины ввода). stackoverflow.com/questions/1660501/ - person Arc; 18.09.2010

Вы можете просто создать общую библиотеку на C # и использовать класс FileInfo для получения полного пути к каталогу или файлу. Затем используйте .GetHashCode () в пути, например:

Hash = fullPath.GetHashCode();

or

int getHashCode(string uri) 
{
   if (uri == null) throw new ArgumentNullException(nameof(uri));

   FileInfo fileInfo = new FileInfo(uri);
   return fileInfo.FullName.GetHashCode();
}

Хотя это всего лишь 32-битный код, вы дублируете его или добавляете другой HashCode на основе некоторых других характеристик файла.

person reinier    schedule 01.11.2016
comment
OP ищет алгоритм хеширования, а вы предлагаете встроить функцию GetHashCode C # в общую библиотеку? - person arainone; 20.02.2018