CRC32 в Python (против CRC32b)

Я пытаюсь сгенерировать некоторые хэши crc32, но похоже zlib а также binascii использовать алгоритм crc32b, хотя их соответствующие функции просто zlib.crc32 а также binascii.crc32, Существуют ли другие ресурсы Python для генерации хэша, которые я могу попробовать? Интересно, что ранее я обнаружил, что пакет R digest также реализует crc32b без упоминания о crc32.

Некоторые примеры того, что я имею в виду под CRC32 и CRC32b:

Здесь вы можете увидеть как в раскрывающемся списке: http://www.md5calc.com/crc32

Здесь CRC32b находится на правой стороне: https://hash.online-convert.com/crc32-generator

Вот php-центрированная дискуссия о дистрибуции: в чем разница между crc32 и crc32b?

Здесь мы видим, что Python реализует CRC32b: Как рассчитать CRC32 с Python для соответствия онлайн-результатам?

Спасибо

2 ответа

Решение

То, что они называют "crc32", - это CRC-32/BZIP2 в этом каталоге. То, что они называют "crc32b", - это PKZip CRC-32 (ITU V.42), обычно называемый просто CRC-32, как и в этом каталоге. Такое использование "crc32" и "crc32b", по-видимому, является нотацией, изобретенной авторами PHP.

Вы можете найти множество примеров хэшей на странице документации PHP дляhash(), Там вычисляются хэши строки "привет", и их можно проверить по реализациям. В связанном каталоге используется "123456789" для проверки.

Вы можете легко рассчитать CRC BZIP2 самостоятельно. Вот некоторый код C в качестве примера:

uint32_t crc32bzip2(uint32_t crc, void const *mem, size_t len) {
    unsigned char const *data = mem;
    if (data == NULL)
        return 0;
    crc = ~crc;
    while (len--) {
        crc ^= (unsigned)(*data++) << 24;
        for (unsigned k = 0; k < 8; k++)
            crc = crc & 0x80000000 ? (crc << 1) ^ 0x4c11db7 : crc << 1;
    }
    crc = ~crc;
    return crc;
}

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

Версия Python, которая вычисляет CRC-32/BZIP2 байтов из stdin:

#!/usr/local/bin/python3
import sys
a = bytearray(sys.stdin.buffer.read())
crc = 0xffffffff
for x in a:
    crc ^= x << 24;
    for k in range(8):
        crc = (crc << 1) ^ 0x04c11db7 if crc & 0x80000000 else crc << 1
crc = ~crc
crc &= 0xffffffff
print(hex(crc))

crcany будет генерировать более эффективные версии на основе таблиц (в C), если это необходимо.

Я сделал несколько улучшений в ответе Марка Адлера, он быстрее в 20 и более раз после разделения данных на разделы, но я не знаю почему.

#!/usr/local/bin/python3
import random
import timeit

def crc32_bzip2(data, precrc=None, bs=None):
    def crc32_bzip2_block(data, precrc=None):
        crc = 0xFFFFFFFF if precrc is None else (precrc ^ 0xFFFFFFFF)
        for x in data:
            crc ^= x << 24
            for k in range(8):
                if crc & 0x80000000:
                    crc = (crc << 1) ^ 0x04C11DB7
                else:
                    crc = crc << 1
        crc = ~crc
        crc &= 0xFFFFFFFF
        return crc

    crc = None
    bs = bs if bs else len(data)
    blocks = [data[i:i+bs] for i in range(0, len(data), bs)]
    for b in blocks:
        crc = crc32_bzip2_block(b, crc)
    return crc


# testing
bs = 512
datasize = 1024 * 50
data = bytearray(random.getrandbits(8) for _ in range(datasize))

number = 1
setup = 'from __main__ import crc32_bzip2, data, bs'
a = timeit.timeit('crc32_bzip2(data)', setup=setup, number=number)
b = timeit.timeit('crc32_bzip2(data, bs=bs)', setup=setup, number=number)

print(f'{a:.3}', f'{b:.3}', f'{a/b:.3}', sep='\t')
# 3.66  0.127   28.8, on the environment:
#    Intel i5-6300U CPU notebook
#    Python 3.6.6 64bit
#    Windows 7 SP1 64bit
Другие вопросы по тегам