2015-05-07 22 views
6

Sto provando a calcolare/generare l'hash CRC32 di alcune stringhe casuali usando Python ma non corrispondono ai valori che ho generato da fonti online. Ecco quello che sto facendo sul mio PC,Come calcolare CRC32 con Python per abbinare i risultati online?

>>> import binascii 
>>> binascii.crc32('hello-world') 
-1311505829 

Un altro approccio,

>>> import zlib 
>>> zlib.crc32('hello-world') 
-1311505829 

Il fatto che i risultati di cui sopra sono identici mi dice che sto chiamando la funzione correttamente. Ma, se vado alle seguenti fonti online,

Per la stringa "ciao-mondo" tutti dare lo stesso valore = b1d4025b

Qualcuno sa cosa devo fare per ottenere risultati corrispondenti?

Mentre stavo scrivendo questa domanda mi venne in mente che potrei avere bisogno di convertire il mio risultato Python in esadecimale,

>>> hex(zlib.crc32('hello-world')) 
'-0x4e2bfda5' 

Purtroppo, questo non ha aiutato neanche. :(

+0

questo è il CRC32 corretto di "ciao-mondo", cosa ti aspetti di essere il CRC32? – Yeo

+2

@Yeo: Il CRC32 corretto di 'ciao-mondo' è' 0xb1d4025b' come un int unsigned, '-0x4e2bfda5' come int firmato. Chiaramente non sa come questi due valori sono correlati, quindi la domanda. – abarnert

risposta

13

Python sta facendo un segno a 32 bit CRC

Questi siti stanno facendo un unsigned CRC a 32 bit

I valori sono gli stessi in caso contrario, come si può vedere da questo:..

>>> 0x100000000 - 0xb1d4025b == 0x4e2bfda5 
True 

Un modo rapido per la conversione da 32 bit con segno a 32 bit senza segno è: *

>>> -1311505829 % (1<<32) 
2983461467 

Oppure, in esadecimale:

>>> hex(-1311505829 % (1<<32)) 
'0xb1d4025b' 

& 0xFFFFFFFF o % 0x100000000 o & (2**32-1) o % (2**32) e così via sono tutti modi equivalenti a fare lo stesso bit-giocherellando; si riduce a quello che trovi più leggibile.


* Questo funziona solo in lingue che fanno divisione intera pavimento, come Python (-3 // 2 == -2); nelle lingue che eseguono la divisione intera troncata, come Java (-3/2 == -1), si finisce comunque con un numero negativo. E in lingue che non hanno nemmeno richiedono che la divisione e mod vanno insieme correttamente, come C, tutte le scommesse sono fuori, ma in C, si era appena gettato i byte per il tipo che si desidera ...

+1

Penso che tu abbia confuso troncatura e pavimento. – user2357112

+0

@ user2357112: Grazie; fisso. – abarnert

9

zlib.crc32 documentation suggerisce di utilizzare il seguente approccio "per generare lo stesso valore numerico su tutte le versioni e piattaforme Python".

import zlib 
hex(zlib.crc32(b'hello-world') & 0xffffffff) 

Il risultato è 0xb1d4025b come previsto.

+0

Su alcune piattaforme verrà firmato, altri non firmati. Questo non aiuta l'OP, che è su una piattaforma dove è stato firmato. – abarnert

+0

Sono curioso del perché questo sarebbe diverso tra le piattaforme. Il comportamento di Python non sarebbe identico su tutta la linea? (ignorando le differenze 2.xe 3.x) – chronodekar

+0

@ sincronodekar: sono sicuro che non sarebbe troppo difficile da trovare nella fonte; se non riesci a trovarlo da solo, puoi creare una nuova domanda. Ma da un test rapido, è negativo su Mac 2.7 e Linux 2.7, positivo su Windows 2.7 e Mac 3.5, quindi sono abbastanza sicuro che sia un problema di piattaforma, non un problema 2 contro 3. O forse è una combinazione dei due. (Indipendentemente da ciò, non aiuta l'OP, il cui Python ha chiaramente firmato crc32, proprio come il mio Mac 2.7 ...) – abarnert

3

Sembra che python restituisca un intero con segno (da cui il numero negativo), mentre gli altri restituiscono un intero con segno.

Ho provato a utilizzare un modulo con 2^32 e ha fornito lo stesso valore di questi siti.

>>> hex(zlib.crc32('hello-world')% 2**32))       
'0xb1d4025b'