2016-02-07 3 views
0

Я пытаюсь использовать функцию crc32_combine от zlib в Python. Хотя доступны различные другие функции zlib, этот не входит в стандартную библиотеку «с батареями». Я пробовал два подхода: порт из кода C в Python и вызов zlib из Python с помощью ctypes. Оба дают мне разные результаты, хотя и не результат, которого я ожидаю. Я представляю код ctypes, так как я думаю, что это выполняется быстрее и имеет меньший шанс для дополнительных ошибок программиста.Использование zlib crc32_combine в Python

Алгоритм может быть combine two CRC32 хешей, когда указана длина данных данных второго хэша. crc32_combine определяется следующим образом:

crc32(crc32(0, seq1, len1), seq2, len2) == crc32_combine(
    crc32(0, seq1, len1), crc32(0, seq2, len2), len2) 

Это выход:

Expected CRC: 45E57586 
Combined CRC: 567EE4E4 

Вторая линия всегда отличается, когда бежал с Python 3.5.1 на win32. Не с Python 2, но результат не то, что я ожидаю. Поместите zlib1.dll в тот же каталог, что и скрипт, чтобы попробовать его.

import zlib 

def crc32_combine_ctypes(crc1, crc2, len2): 
    import ctypes 
    from ctypes import util 

    lib = util.find_library('zlib1') 
    _zlib = ctypes.CDLL(lib) 
    assert _zlib._name, "Can't find zlib" 

    _zlib.crc32_combine.argtypes = [ 
     ctypes.c_ulong, ctypes.c_ulong, ctypes.c_ulong] 
    _zlib.crc32_combine.restype = ctypes.c_ulong 

    return _zlib.crc32_combine(crc1, crc2, len2) 

testfile = "zlib1.dll" 

with open(testfile, "rb") as tf: 
    data = tf.read() 

print("Expected CRC: %0.8X" % (zlib.crc32(data) & 0xFFFFFFFF)) 

cut = len(data) // 2 - 100 
p1 = data[0:cut] 
p2 = data[cut:] 

crc1 = zlib.crc32(p1) 
crc2 = zlib.crc32(p2) 
len1 = len(p1) 
len2 = len(p2) 

combined = crc32_combine_ctypes(crc1, crc2, len2) 
print("Combined CRC: %0.8X" % (combined & 0xFFFFFFFF)) 

Что я делаю неправильно?

+2

Там что-то не так с этим 32-битной сборки zlib1.dll. На моей собственной 64-битной сборке (только этой функции) объединенный результат соответствует ожидаемому результату. Чтобы создать DLL, я загрузил [источник] (http://gnuwin32.sourceforge.net/downlinks/zlib-src-zip.php) из вашей ссылки, скопировал определения 'crc32_combine',' gf2_matrix_times' и 'gf2_matrix_square' из crc32.c и построил его как 64-битную DLL. – eryksun

+0

Эта [32-разрядная сборка] (http://prdownloads.sourceforge.net/libpng/zlib128-dll.zip?download) также работает так, как ожидалось. – eryksun

+0

Плохая DLL была проблема! Как-то я не следил и не видел других ссылок на домашней странице zlib и выбрал плохой :) – Gfy

ответ

1

eryksun имел правильную идею: я использовал плохую и старую DLL. Последняя версия Zlib с DLL в 32 битном включены: https://sourceforge.net/projects/libpng/files/zlib/1.2.8/

Мой порт чистый код Python является несколько сотен раз медленнее, чем вызов библиотеки с ctypes. (номера с использованием timeit с 1к итераций и 50м в качестве параметра длины)

31.729 (function provided below) 
0.120 (just the _zlib.crc32_combine() call: no library loading included) 

Чистый код Python:

def crc32_combine(crc1, crc2, len2): 
    """Explanation algorithm: https://stackoverflow.com/a/23126768/654160 
    crc32(crc32(0, seq1, len1), seq2, len2) == crc32_combine(
     crc32(0, seq1, len1), crc32(0, seq2, len2), len2)""" 
    # degenerate case (also disallow negative lengths) 
    if len2 <= 0: 
     return crc1 

    # put operator for one zero bit in odd 
    # CRC-32 polynomial, 1, 2, 4, 8, ..., 1073741824 
    odd = [0xedb88320] + [1 << i for i in range(0, 31)] 
    even = [0] * 32 

    def matrix_times(matrix, vector): 
     number_sum = 0 
     matrix_index = 0 
     while vector != 0: 
      if vector & 1: 
       number_sum ^= matrix[matrix_index] 
      vector = vector >> 1 & 0x7FFFFFFF 
      matrix_index += 1 
     return number_sum 

    # put operator for two zero bits in even - gf2_matrix_square(even, odd) 
    even[:] = [matrix_times(odd, odd[n]) for n in range(0, 32)] 

    # put operator for four zero bits in odd 
    odd[:] = [matrix_times(even, even[n]) for n in range(0, 32)] 

    # apply len2 zeros to crc1 (first square will put the operator for one 
    # zero byte, eight zero bits, in even) 
    while len2 != 0: 
     # apply zeros operator for this bit of len2 
     even[:] = [matrix_times(odd, odd[n]) for n in range(0, 32)] 
     if len2 & 1: 
      crc1 = matrix_times(even, crc1) 
     len2 >>= 1 

     # if no more bits set, then done 
     if len2 == 0: 
      break 

     # another iteration of the loop with odd and even swapped 
     odd[:] = [matrix_times(even, even[n]) for n in range(0, 32)] 
     if len2 & 1: 
      crc1 = matrix_times(odd, crc1) 
     len2 >>= 1 

     # if no more bits set, then done 
    # return combined crc 
    crc1 ^= crc2 
    return crc1 
Смежные вопросы