logo

Acerca de

Bienvenido a mi blog, el sitio perfecto para mis inquietudes, experiencias e idas de olla sobre temas de hoy en día.

Historia al azar

Categorías

Últimas entradas

Últimos comentarios

Enlaces

Meta

photo Luis PeraltaEstado Jabber
Ziritione
Castellón Spain
39.997638, -0.064030

Sindica

Sindícame, por cortesía del subliminal Atom.

15 octubre 2008

Hace un tiempo conté cómo generar un hash FNV con Python, esta vez le ha tocado al PHP. En principio la traducción debería haber sido directa, salvo porque el cabroncete del PHP y las operaciones sobre bits con número de tamaño mayor a 32 bits no se llevan nada bien. Vamos, es que es básico. Así que solución apoyándonos en la librería GMP y su extensión para PHP.

function FNV1a32_hash($str) {
        $prime = "16777619";
        $h = "2166136261";
        $i = 0;
        $s = strlen($str);

        while ($i<$s) {
                $h = gmp_xor($h, ord($str[$i++]));
                $h = gmp_mul($h, $prime);
        }
        return dechex((float)gmp_strval(gmp_and($h, "0x00000000ffffffff")));
}
29 enero 2008

Los hashes o resúmenes FNV (de Fowler / Noll / Vo) son útiles por varias razones:

  • Es muy rápido generarlos
  • El tamaño del hash es fácilmente manipulable
  • Se portan muy bien, es decir, producen pocas colisiones

Pues hoy necesitaba usarlos con mi querido Python y curiosamente nadie lo había implementado. Así que no me ha quedado más remedio que ponerme (no sé quién me ha dicho esta tarde que eso sería sólo un algoritmo, que no tendría complicación... en cuanto lo recuerde se va a acordar). Por si a alguien le viene bien:

def FNV1a32(key):
    fnv_prime = long(0x1000193)
    hash = long(0x811C9DC5)
    for i in range(len(key)):
      hash ^= ord(key[i])
      hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24)
    return (hash & 0x00000000ffffffffL)

def FNV132(key):
    fnv_prime = long(0x1000193)
    hash = long(0x811C9DC5)
    for i in range(len(key)):
      hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24)
      hash ^= ord(key[i])
    return (hash & 0x00000000ffffffffL)

La diferencia entre FNV132 y FNV1a32 es el orden en el que se hace la multiplicación. Y aquí sólo he puesto los métodos que calculan el hash de 32 bits, en la referencia de arriba tenéis cómo hacer para generarlos variables (escoger un buen primo inicial, fnv_prime, y un valor inicial del hash, hash, adecuados y quedarnos sólo con la parte del resultado que nos interese).