Calcular el hash CRC32


14

Créditos

Este desafío se originó en @miles .


Cree una función que calcule el hash CRC32 de una cadena de entrada. La entrada será una cadena ASCII de cualquier longitud. La salida será el hash CRC32 de esa cadena de entrada.

Explicación

El algoritmo de CRC32 y otros CRC son esencialmente los mismos, por lo que aquí solo se demostrará CRC3.

En primer lugar, tiene el polinomio generador, que en realidad es un entero de 4 bits [n + 1] (sería 33 bits en CRC32).

En este ejemplo, el polinomio generador es 1101.

Luego, tendrá la cadena para hacer hash, que en este ejemplo sería 00010010111100101011001101.

00010010111100101011001101|000 (1)    append three [n] "0"s
   1101                        (2)    align with highest bit
00001000111100101011001101|000 (3)    XOR (1) and (2)
    1101                       (4)    align with highest bit
00000101111100101011001101|000 (5)    XOR (3) and (4)
     1101                      (6)    align with highest bit
00000011011100101011001101|000 (7)    XOR (5) and (6)
      1101                     (8)    align with highest bit
00000000001100101011001101|000 (9)    XOR (7) and (8)
          1101                 (10)   align with highest bit
00000000000001101011001101|000 (11)   XOR (9) and (10)
             1101              (12)   align with highest bit
00000000000000000011001101|000 (13)   XOR (11) and (12)
                  1101         (14)   align with highest bit
00000000000000000000011101|000 (15)   XOR (13) and (14)
                     1101      (16)   align with highest bit
00000000000000000000000111|000 (17)   XOR (15) and (16)
                       110 1   (18)   align with highest bit
00000000000000000000000001|100 (19)   XOR (17) and (18)
                         1 101 (20)   align with highest bit
00000000000000000000000000|001 (21)   XOR (19) and (20)
^--------REGION 1--------^ ^2^

El resto obtenido en (21), cuando la región 1 es cero, es decir 001, sería el resultado del hash CRC3.

Especificaciones

  • El polinomio generador es 0x104C11DB7, o 0b100000100110000010001110110110111, o 4374732215.
  • La entrada puede ser una cadena o una lista de enteros, o cualquier otro formato razonable.
  • La salida puede ser una cadena hexadecimal o simplemente un número entero, o cualquier otro formato razonable.
  • Los elementos integrados que calculan el hash CRC32 no están permitidos.

Objetivo

Se aplican las reglas estándar para el .

El código más corto gana.

Casos de prueba

input         output      (hex)
"code-golf"   147743960   08CE64D8
"jelly"       1699969158  65537886
""            0           00000000

Si entiendo bien, esto es hacer la división polinómica módulo 2 y encontrar el resto, es decir, el análogo de mod en la multiplicación XOR .
xnor

1
Sí. Sin embargo, este no es el módulo xnor , este es el módulo xor.
Leaky Nun

Para CRC32, ¿primero agrega 31 0?
xnor

Sí - - - - - - - - -
Leaky Nun

1
@KennyLau puede hacer ping a las personas con su nombre, al igual que el chat.
Rɪᴋᴇʀ

Respuestas:


12

Intel x86, 34 30 29 27 bytes

Toma la dirección de la cadena terminada en cero en ESI y devuelve el CRC en EBX:

31 db ac c1 e0 18 74 01 31 c3 6a 08 59 01 db 73 
06 81 f3 b7 1d c1 04 e2 f4 eb e7

Desmontaje (sintaxis de AT&T):

00000000    xorl    %ebx, %ebx
00000002    lodsb   (%esi), %al
00000003    shll    $24, %eax
00000006    je      0x9
00000008    xorl    %eax, %ebx
0000000a    pushl   $8
0000000c    popl    %ecx
0000000d    addl    %ebx, %ebx
0000000f    jae     0x17
00000011    xorl    $0x4c11db7, %ebx
00000017    loop    0xd
00000019    jmp     0x2
0000001b

Incorporando sugerencias de Peter Cordes para guardar cuatro bytes más. Esto supone una convención de llamada donde el indicador de dirección para las instrucciones de cadena se borra en la entrada.

Incorporación de la sugerencia de Peter Ferrie de usar push literal y pop para cargar una constante, guardando un byte.

Incorporando la sugerencia de Peter Ferrie de saltar al segundo byte de una xorl %eax, %ebxinstrucción que es una retlinstrucción, combinada con cambiar la interfaz de la rutina para tomar una cadena terminada en cero en lugar de longitud, ahorrando dos bytes en total.


Use una convención de llamada que requiera que se borre el indicador de dirección al ingresar, para que pueda guardar el cldinsn (como hice en mi respuesta adler32 ). ¿Es una práctica normal permitir convenciones de llamadas totalmente arbitrarias para respuestas asm?
Peter Cordes

De todos modos, parece que su código funcionará como código de máquina x86-64, y podría usar la convención de llamadas x86-64 SysV x32 para contar ediy el puntero adentro esi(tal vez no sea de extensión cero, así que tal vez evite las cosas y requiera un Puntero de 64 bits con extensión cero). (x32 para que pueda usar matemática de puntero de 32 bits de forma segura, pero aún tenga la convención de llamadas de registro-argumentos. Como no usa inc, no hay inconveniente en el modo largo.)
Peter Cordes

¿Consideró mantener edxen orden de byte invertido? bswap edxes solo 2B. shr %edxes 2B, igual que su desplazamiento a la izquierda conadd %edx,%edx . Esto probablemente no sea útil; A menos que permita una mayor optimización, ahorrará 3B para el shl $24, %eax, pero gastará 4B xor %eax,%eaxal principio y bswap %edxal final. Zeroing eax te permite usarlo cdqa cero %edx, por lo que en general es un lavado. Sin embargo, funcionaría mejor: evita que el bloqueo / desaceleración del registro parcial en cada iteración escriba aly luego lea eaxcon shl. : P
Peter Cordes

1
Me confundí con la pregunta Adler-32, que tiene un límite de longitud. Esta pregunta no tiene un límite de longitud explícito.
Mark Adler

1
Puede haber una manera de acortar esto con la instrucción PCLMULQDQ. Sin embargo, su uso tiende a necesitar muchas constantes, por lo que posiblemente no.
Mark Adler


4

Ruby, 142 bytes

Función anónima; toma una cadena como entrada, devuelve un entero.

->s{z=8*i=s.size;r=0;h=4374732215<<z
l=->n{j=0;j+=1 while 0<n/=2;j}
s.bytes.map{|e|r+=e*256**(i-=1)};r<<=32
z.times{h/=2;r^=l[h]==l[r]?h:0}
r}

2
¿Puedes cambiar tu nombre para que las personas puedan distinguirnos? XD
Leaky Nun

2
@KennyLau tienes que ser tan exigente ... bien OK
Valor de tinta

Solo bromeaba xd
Leaky Nun

4

Jalea , 23 bytes

ḅ⁹Bµ4374732215B×ḢḊ^µL¡Ḅ

La entrada está en forma de una lista de enteros. Pruébalo en línea! o verificar todos los casos de prueba .

Cómo funciona

Si bien Jelly tiene XOR bit a bit, rellenar la entrada con ceros y alinear el polinomio con el dígito binario más significativo hace que este enfoque, que utiliza listas de bits, sea un poco más corto.

ḅ⁹Bµ4374732215B×ḢḊ^µL¡Ḅ  Main link. Argument: A (list of bytes)

ḅ⁹                       Convert A from base 256 to integer.
  B                      Convert the result to binary, yielding a list.
   µ                     Begin a new, monadic chain. Argument: B (list of bits)
    4374732215B          Convert the integer to binary, yielding a list.
                Ḣ        Pop and yield the first, most significant bit of B.
               ×         Multiply each bit in the polynomial by the popped bit.
                 ^       Compute the element-wise XOR of both lists.
                         If one of the lists is shorter, the elements of the other
                         lists do not get modified, thus avoiding the necessity
                         of right-padding B with zeroes.
                  µ      Convert the previous chain into a link.
                   L¡    Execute the chain L times, where L is the number of bits
                         in the original bit list.
                     Ḅ   Convert from binary to integer.


3

CJam, 37 36 bytes

q256b32m<{Yb4374732215Yb.^Yb_Yb32>}g

Pruébalo aquí.

Explicación

q               e# Read input.
256b            e# Convert to single number by treating the character codes
                e# as base-256 digits.
32m<            e# Left-shift the number by 32 bits, effectively appending 32
                e# zeros to the binary representation.
{               e# While the condition on top of the stack is truthy...
  Yb            e#   Convert the number to base 2.
  4374732215Yb  e#   Convert the polynomial to base 2.
  .^            e#   Take the bitwise XOR. If the number is longer than the
                e#   polynomial, the remaining bits will be left unchanged.
  Yb            e#   Convert the list back from base 2, effectively stripping
                e#   leading zeros for the next iteration.
  _             e#   Duplicate the result.
  Yb            e#   Convert back to base 2.
  32>           e#   Remove the first 32 bits. If any are left, continue the loop.
}g

q256bYb_,{(4374732215Ybf*1>.^}*YbGuarda algunos bytes.
Dennis

@Dennis Eso es muy inteligente, no dude en responderlo por separado. :)
Martin Ender

3

Pyth, 28 bytes

uhS+GmxG.<C"Á·"dlhG.<Cz32

Pruébelo en línea: Demostración o conjunto de pruebas

Explicación:

uhS+GmxG.<C"..."dlhG.<Cz32   implicit: z = input string
                      Cz     convert to number
                    .<  32   shift it by 32 bits
u                            apply the following expression to G = ^,
                             until it get stuck in a loop:
     m           lhG            map each d in range(0, log2(G+1)) to:
          C"..."                   convert this string to a number (4374732215)
        .<      d                  shift it by d bits
      xG                           xor with G
   +G                           add G to this list
 hS                             take the minimum as new G

2

JavaScript (ES6), 180 bytes

f=(s,t=(s+`\0\0\0\0`).replace(/[^]/g,(c,i)=>(c.charCodeAt()+256*!!i).toString(2).slice(!!i)))=>t[32]?f(s,t.replace(/.(.{32})/,(_,m)=>(('0b'+m^79764919)>>>0).toString(2))):+('0b'+t)

La falta de un operador XOR de 33 bits, o incluso un operador XOR de 32 bits sin firmar, no es útil.


1

CJam, 33 bytes

q256bYb_,{(4374732215Ybf*1>.^}*Yb

La entrada está en forma de una cadena. Pruébalo en línea!

Cómo funciona

q                                  Read all input from STDIN.
 256bYb                            Convert it from base 256 to base 2.
       _,{                   }*    Compute the length and repeat that many times:
          (                          Shift out the first bit.
           4374732215Yb              Convert the integer to base 2.
                       f*            Multiply each bit by the shifted out bit.
                         1>          Remove the first bit.
                           .^        Compute the element-wise XOR of both lists.
                                     If one of the lists is shorter, the elements
                                     of the other lists do not get modified, thus
                                     avoiding the necessity of right-padding B with
                                     zeroes.
                               Yb  Convert the final result from base 2 to integer.
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.