Инкрементные контрольные суммы

Я ищу алгоритм контрольной суммы, где для большого блока данных контрольная сумма равна сумме контрольных сумм из всех меньших блоков компонентов. Большинство из того, что я нашел, это RFCs 1624/1141, которые предоставляют эту функциональность. Кто-нибудь имеет опыт работы с этими методами контрольных сумм или схожим?

Ответ 1

Я использовал только контрольные суммы Adler/Fletcher, которые работают, как вы описываете.

Существует хорошее сравнение реализаций хешей/контрольной суммы crypto ++ здесь.

Ответ 2

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

Алгоритм CRC-32 так же прост, как это:

uint32_t update(uint32_t state, unsigned bit)
{
    if (((state >> 31) ^ bit) & 1) state = (state << 1) ^ 0x04C11DB7;
    else                           state = (state << 1);
    return state;
}

Математически состояние представляет собой многочлен над полем GF2, который всегда приводится по модулю образующего многочлена. Учитывая новый бит b, старое состояние преобразуется в новое состояние, подобное этому

state --> (state * x^1 + b * x^32) mod G

где G - образующий многочлен, а сложение выполнено в GF2 (xor). Эта контрольная сумма является линейной в том смысле, что вы можете написать сообщение M как сумму (xor) сообщений A, B, C,... как это

  10110010 00000000 00000000 = A =    a     00000000 00000000
  00000000 10010001 00000000 = B = 00000000    b     00000000
  00000000 00000000 11000101 = C = 00000000 00000000    c
-------------------------------------------------------------
= 10110010 10010001 11000101 = M =    a        b        c

со следующими свойствами

         M  =          A  +          B  +          C
checksum(M) = checksum(A) + checksum(B) + checksum(C)

Опять же, я имею в виду + в GF2, который вы можете реализовать с помощью двоичного XOR.

Наконец, можно вычислить checksum(B) на основе checksum(B) и положение субблока b относительно b. Простая часть - это ведущие нули. Ведущие нули вообще не влияют на контрольную сумму. Итак, checksum(0000xxxx) совпадает с checksum(xxxx). Если вы хотите вычислить контрольную сумму нулевого запаса (вправо → завершающие нули) с учетом контрольной суммы непроложенного сообщения, это немного сложнее. Но не так сложно:

zero_pad(old_check_sum, number_of_zeros)
  := ( old_check_sum *  x^{number_of_zeros}        ) mod G
   = ( old_check_sum * (x^{number_of_zeros} mod G) ) mod G

Итак, получение контрольной суммы сообщения с нулевым дополнением - это просто вопрос о умножении "полинома контрольной суммы" непроложенного сообщения с другим полиномом (x^{number_of_zeros} mod G), который зависит только от количества нулей добавить. Вы можете прекомпилировать это в таблице или использовать алгоритм с квадратным умножением, чтобы быстро вычислить эту мощность.

Рекомендуемое чтение: Безболезненное руководство по алгоритмам обнаружения ошибок CRC

Ответ 3

Чтобы ответить на вопрос Amigable Clark Kent bounty, для целей идентификации файлов вы, вероятно, хотите использовать криптографическую хеш-функцию, которая пытается гарантировать, что любые два заданных файла имеют чрезвычайно низкую вероятность создания одинакового значения, в отличие от контрольной суммы, которая является обычно используется только для обнаружения ошибок и может предоставлять одинаковое значение для двух очень разных файлов.

Многие криптографические хэш-функции, такие как MD5 и SHA-1, используйте конструкцию Merkle-Damgård, в которой есть расчет, чтобы сжать блок данных в фиксированный размер, а затем объединить это значение с фиксированным размером из предыдущего блока (или вектором инициализации для первого блока). Таким образом, они могут работать в потоковом режиме, постепенно вычисляя по мере их продвижения.