Nano Hash - криптовалюты, майнинг, программирование

Последовательное хеширование структуры до 32 бит

У меня есть структура, имеющая 3 целых числа в [1, 1000] и строку.

Мне нужно представить его в виде 32-битного числа, чтобы две структуры, отличающиеся хотя бы одним полем, давали разные коды, а структуры с одинаковым содержимым постоянно давали один и тот же код. Обычно одно из целочисленных полей увеличивается на несколько единиц. Это обязательно должно привести к другому коду.

Сначала я думал отформатировать поля структуры в строку в константном формате, а затем хэшировать ее с помощью функции GetHashCode класса String. Но затем я прочитал здесь в некоторых обсуждениях, что повторяющиеся процессы, выполняемые на одном и том же входе, не обязательно производят один и тот же хеш-выход. Прежде всего, верно ли это для .NET 4? Для меня это важно, потому что хэш-значения должны сохраняться и оставаться согласованными во время выполнения процесса. Я также видел здесь предложения выполнять побитовые операции с результатами платформы GetHashCode, применяемыми к каждому полю структуры с использованием простых чисел. Но и здесь, видимо, я не могу рассчитывать на стабильный результат запуска процесса.

Если я использую криптографические хэш-функции, я превышаю 32 бита.

Если бы у меня не было строкового поля, я бы составил код в виде 32-битного массива из числовых полей. Может быть, стоит выполнить операцию XOR над таким битовым массивом со строковым полем GetHashCode? Увеличиваю ли я вероятность того, что повторный запуск некоторых входных данных приведет к тому же результату хеширования?

Что бы вы предложили сделать?

04.03.2013

  • Вам нужен идеальный хеш, если вы хотите избежать коллизий. Можете ли вы однозначно описать каждую из ваших структур всего за 32 бита? Кроме того, у вас нет гарантий относительно стабильности встроенных хеш-функций (и вы не должны этого делать). Так для чего вы используете этот хэш? 05.03.2013
  • возможный дубликат Создайте хэш-код из двух чисел 05.03.2013
  • @sixlettervariables Для идеального хэша нужно заранее знать все пространство значений, верно? (И чтобы он содержал менее 2**32 элементов.) 05.03.2013
  • @user2132086 user2132086: Являются ли все четыре поля частью идентификации структуры или одно или несколько из них являются просто атрибутом (если заимствовать терминологию БД)? 05.03.2013
  • @PieterGeerkens Да, все поля вместе объединяют ключ 05.03.2013
  • @user2132086 user2132086: так почему ключ должен быть 32-битным? Кроме того, вам, вероятно, не нужен хэш-код как таковой, так как вы столкнетесь с некоторыми проблемами реализации, если попытаетесь их сохранить. 05.03.2013

Ответы:


1

Если у вас было следующее:

struct 
{
    int A;
    int B;
    int C;
}

Предполагая, что A, B, C находятся в диапазоне [1, 1000]. Можно создать «идеальный хэш» (без коллизий), поскольку A, B, C могут иметь каждые 1000 различных возможных значений. Действительно, log2(1000^3) <= 32 (1000^3 — это количество возможных значений структуры, а log2 используется для получения количества битов, необходимых для хранения всех этих значений без коллизий, а 32 — это количество битов целого числа).

int MyHashCode()
{
    return 1000 * (1000 * (A - 1) + (B - 1)) + (C - 1);  // There is no overflow or collision since A, B, C are in the range [1, 1000]
}

Мы можем упростить его, используя более слабое условие: A, B, C находятся в диапазоне [0, 1000]:

int MyHashCode()
{
    return 1001 * (1001 * A + B) + C;  // There is no overflow or collision since A, B, C are in the range [0, 1000]
}

Обновлять

Учитывая, что ваша структура содержит строку внутри нее. То, чего вы хотите достичь, невозможно. Потому что строка может представлять бесконечное количество значений.

Если бы это было возможно, можно было бы создать очень мощный алгоритм сжатия. Это может хранить любой файл в... 32-битном числе! Математически это происходит из-за того, что инъективная функция может отображать только большее пространство.

04.03.2013
  • Поскольку существует более 2**32 возможных файлов, такой алгоритм сжатия доказуемо не может существовать ;) (Хорошо, технически, алгоритм сжатия может, если вам никогда не понадобится < i>алгоритм распаковки.) 05.03.2013
  • @millimoose Вы правы! Создадим самый мощный алгоритм сжатия: x =› 0. 05.03.2013
  • @CédricBignon Мое строковое поле представляет собой имя машины, поэтому можно сделать некоторые предположения, такие как ограничение длины, но я не понимаю, как это помогает :-) 05.03.2013
  • @user2132086 user2132086 За исключением того, что строка может иметь максимум 4 разных значения, вы не сможете сделать идеальный хеш для этого на 32-битной системе. (Почему 4? Потому что 2^32/1000^3 = 4,29...) 05.03.2013

  • 2

    Анонимные типы имеют автогенерированную разумную GetHashCode() реализацию. Я бы попробовал просто использовать:

    struct MyStruct 
    {
        int _intField1;
        int _intField2;
        int _intField3;
        string _stringField;
    
        public long GetHashCode() 
        {
            return new { _intField1, _intField2, _intField3, _stringField }.GetHashCode();
        }
    }
    

    Поскольку и int, и string являются неизменяемыми типами, хэш-код должен оставаться одним и тем же между запусками приложения, если базовая версия платформы .NET остается неизменной. (Это может быть или не быть «достаточно стойким».)

    Тем не менее, это может измениться, если изменится внутренняя реализация GetHashCode(). В этом случае используйте криптографический хэш. Неважно, что он превышает 32 бита, потому что криптографические хэши предназначены для получения совершенно разных результатов при небольших изменениях ввода. Это означает, что для двух разных входных данных любые заданные 32 бита хеш-кода вряд ли будут равны. Просто используйте BitConverter.ToInt32() для преобразования любой части хэша, которую вы хочу int.

    Кроме того, очевидно, что это сделает несколько маловероятным, что две разные структуры будут генерировать разные хеш-коды. (Это можно определить, используя приблизительную формулу парадокса дня рождения, если я правильно читаю вики, это означает, что у вас будет 10% шанс получить дубликаты, когда вы сохраните ~140 000 ~30 000 записей. , Предполагая, что криптографический хеш имеет идеальные свойства. Я не уверен, что вы можете добиться большего успеха без идеального хэша.)

    04.03.2013
  • реализация по умолчанию ссылочного типа GetHashCode нестабильна между порядком выполнения между выполнениями и потоком. 05.03.2013
  • @millimoose Если я использую MD5Cng (я думаю, это должно быть быстрее), могу ли я предположить, что любые 32 бита из них (я пока не знаю, насколько велик обычный результат MD5Cng) уникальны? 05.03.2013
  • @user2132086 user2132086 Новые хэши (например, SHA256) должны работать лучше, когда речь идет о предотвращении коллизий, но в целом да. Wiki говорит мне, что это свойство называется лавинный эффект, и оно то, чего исследователи криптографии намеренно пытаются достичь. Основная идея состоит в том, что хеш-код для данного сообщения должен выглядеть так, как будто он может быть определен случайным образом. Теперь, очевидно, вы можете получить коллизии, если сделаете случайный выбор из ограниченного пространства значений, но вы можете оценить вероятность их для заданного количества выборов. 05.03.2013
  • @sixlettervariables Мне пока нечего доказывать, но я сильно сомневаюсь, что анонимные типы, в частности, используют реализацию GetHashCode() по умолчанию. Они, безусловно, автоматически генерируют нормальную реализацию Equals(), а это означает, что они также должны автоматически генерировать аналогичную реализацию GetHashCode(), которая в основном работает с хэш-кодами полей (которые в данном случае являются типами value). Я бы поставил доллары на пончики, значения стабильны, по крайней мере, в течение срока службы версии .NET Framework. 05.03.2013
  • @sixlettervariables И глядя на декомпилированный источник для анонимного типа, все, что используется в его реализации GetHashCode(), - это набор констант времени компиляции и EqualityComparer<T>.Default.GetHashCode() для полей, которые в основном делегируют GetHashCode() значений поля. 05.03.2013
  • @millimoose: вы можете предположить, что хэши не изменятся, однако, как доказано, они могут и делают. Лучше не полагаться на реализацию по умолчанию, кроме предоставления стабильного хеш-значения на время выполнения. 05.03.2013
  • @sixlettervariables Я не говорю, что это неразумное безопасное предположение, учитывая тот факт, что документация ничего другого не обещает. Я хочу сказать, что глядя на реализации GetHashCode() для анонимного типа с полями типа значения (-ish), я могу сделать вывод, что для того, чтобы хэши стали нестабильными, потребуются изменения в компиляторе C# и перекомпиляция вашего код или изменение поведения платформы .NET. Если я не прочитал код неправильно, они будут оставаться стабильными в потоках и выполнениях, включающих одни и те же сборки. 05.03.2013
  • @millimoose: он становится нестабильным, только если они меняются во время выполнения. Они более чем приветствуются, чтобы изменить алгоритм между выполнениями... и сделали это между несколькими версиями фреймворка. Таким образом, использование хеш-значения в качестве стабильной ссылки между любыми двумя исполнениями является неправильным. 05.03.2013

  • 3
    1. Сериализуйте свой тип в байт []
    2. Примените общий хеш-алгоритм к байту [], чтобы получить хэш-байт []
    3. Вытащите, например, первые 32 бита байта хеша [] и используйте это
    04.03.2013
  • Если я использую MD5Cng (я думаю, это должно быть быстрее), могу ли я предположить, что первые 32 бита из них (я пока не знаю, насколько велик обычный результат MD5Cng) уникальны? 05.03.2013
  • Вы можете «вроде» предположить, что они уникальны. Если вы сопоставляете объекты размером более 32 бит с 32-битным хэш-кодом, то по так называемому принципу ячейки всегда найдутся два объекта с одинаковым хэш-кодом. Однако вероятность встретить их очень мала. 05.03.2013
  • @TimothyShields Вероятность по крайней мере одного столкновения быстро увеличивается с количеством объектов, которые вы хешируете. 06.03.2013
  • @millimoose Я прекрасно об этом знаю. Первоначальный заданный вопрос заключался в том, как мне детерминистически хэшировать мой пользовательский тип в 32-битный хэш-код? Если вопрос заключается в том, могу ли я использовать 32-битный хеш-код для уникальной идентификации своих объектов, то ответ определенно нет! (См. preshing.com/wp-content/uploads/2011/ 05/small-probabilities.png) 07.03.2013
  • @TimothyShields Хм, эта диаграмма означает, что мое понимание примера обратного парадокса дня рождения в Вики было до смешного неверным, а 32-битные хэши просто совершенно бесполезны, поскольку они достаточно уникальны. 07.03.2013
  • @millimoose Да, именно поэтому я предположил, что первоначальный вопрос на самом деле не требовал истинной уникальности. Для целей использования HashSet<T> это было бы хорошо, но не для идентификатора записи. 07.03.2013
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

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

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..