Python CRC-32 males

Estoy escribiendo un progtwig Python para extraer datos de un archivo bz2 de 6 GB. Un archivo bzip2 se compone de bloques de datos descifrables de manera independiente, por lo que solo necesito encontrar un bloque (están delimitados por bits mágicos), luego crear un archivo bzip2 temporal de un bloque a partir de él en la memoria, y finalmente pasarlo al Función bz2.decompress. Fácil no

El formato bzip2 tiene una sum de comprobación crc32 para el archivo al final. No hay problema, binascii.crc32 al rescate. Pero espera. Los datos que se van a sumr no terminan necesariamente en un límite de bytes, y la función crc32 opera en un número entero de bytes.

Mi plan: Use la función binascii.crc32 en todos menos el último byte, y luego una función mía para actualizar el crc calculado con los últimos 1–7 bits. Pero las horas de encoding y pruebas me han dejado desconcertado, y mi perplejidad puede reducirse a esta pregunta: ¿por qué crc32 (“\ x00”) no es 0x00000000? ¿No debería ser, según el artículo de Wikipedia?

Comienzas con 0b00000000 y rellenas con 32 0, luego haces una división polinómica con 0x04C11DB7 hasta que no queden unidades en los primeros 8 bits, lo cual es inmediato. Sus últimos 32 bits son la sum de comprobación, y ¿cómo puede no ser todos los ceros?

Busqué respuestas en Google y miré el código de varias implementaciones de CRC-32 sin encontrar ninguna pista de por qué esto es así.

    ¿Por qué crc32 (“\ x00”) no es 0x00000000?

    El algoritmo de CRC básico es tratar el mensaje de entrada como un polinomio en GF (2), dividirlo por el polinomio de CRC fijo y usar el rest polinomial como el hash resultante.

    CRC-32 hace una serie de modificaciones en el algoritmo básico:

    1. Los bits en cada byte del mensaje se invierten. Por ejemplo, el byte 0x01 se trata como el polinomio x ^ 7, no como el polinomio x ^ 0.
    2. El mensaje se rellena con 32 ceros en el lado derecho.
    3. Los primeros 4 bytes de este mensaje invertido y rellenado son XOR’d con 0xFFFFFFFF.
    4. El polinomio restante se invierte.
    5. El polinomio restante es XOR con 0xFFFFFFFF.
    6. Y recuerde que el polinomio CRC-32, en forma no inversa, es 0x104C11DB7.

    Trabajemos el CRC-32 de la cadena de un byte 0x00:

    1. Mensaje: 0x00
    2. Invertido: 0x00
    3. Acolchado: 0x00 00 00 00 00
    4. XOR’d: 0xFF FF FF FF 00
    5. El rest cuando se divide por 0x104C11DB7: 0x4E 08 BF B4
    6. XOR’d: 0xB1 F7 40 4B
    7. Invertido: 0xD2 02 EF 8D

    Y ahí lo tienen: el CRC-32 de 0x00 es 0xD202EF8D.
    (Deberías verificar esto)

    Además de la función de decompress un solo disparo, el módulo bz2 también contiene una clase de BZ2Decompressor que descomprime los datos a medida que se alimenta al método de descompresión. Por lo tanto, no le importa la sum de comprobación de fin de archivo y proporciona los datos necesarios una vez que llega al final del bloque.

    Para ilustrar, supongamos que he localizado el bloque que deseo extraer del archivo y lo almacené en una instancia de bitarray.bitarray (probablemente también funcionarán otros módulos de twiddling de bits). Entonces esta función lo decodificará:

     def bunzip2_block(block): from bz2 import BZ2Decompressor from bitarray import bitarray dummy_file = bitarray(endian="big") dummy_file.frombytes("BZh9") dummy_file += block decompressor = BZ2Decompressor() return decompressor.decompress(dummy_file.tobytes()) 

    Tenga en cuenta que los métodos frombytes y tobytes de bitarray se llamaron anteriormente fromstring y tostring .