En informática , se dice que una familia de funciones hash es k -independiente , k -independiente o k -universal [1] si seleccionar una función al azar de la familia garantiza que los códigos hash de cualquier clave k designada sean variables aleatorias independientes (ver definiciones matemáticas precisas a continuación). Estas familias permiten un buen rendimiento de caso promedio en algoritmos aleatorios o estructuras de datos, incluso si los datos de entrada son elegidos por un adversario. Las compensaciones entre el grado de independencia y la eficiencia de la evaluación de la función hash están bien estudiadas, y se han propuesto muchas familias k -independientes.
El objetivo del hash es generalmente mapear claves de un dominio grande (universo) en un rango más pequeño, como contenedores (etiquetados ). En el análisis de algoritmos aleatorios y estructuras de datos, a menudo es deseable que los códigos hash de varias claves se "comportes aleatoriamente". Por ejemplo, si el código hash de cada clave fuera una elección aleatoria independiente en , la cantidad de claves por contenedor podría analizarse utilizando el límite de Chernoff . Una función hash determinista no puede ofrecer tal garantía en un entorno adversario, ya que el adversario puede elegir que las claves sean precisamente la preimagen de un contenedor. Además, una función hash determinista no permite el rehashing : a veces los datos de entrada resultan ser malos para la función hash (por ejemplo, hay demasiadas colisiones), por lo que sería conveniente cambiar la función hash.
La solución a estos problemas es elegir una función aleatoriamente de una gran familia de funciones hash. La aleatoriedad en la elección de la función hash se puede utilizar para garantizar un comportamiento aleatorio deseado de los códigos hash de cualquier clave de interés. La primera definición en esta línea fue el hash universal , que garantiza una baja probabilidad de colisión para dos claves designadas cualesquiera. El concepto de hash independiente, introducido por Wegman y Carter en 1981, [2] fortalece las garantías de comportamiento aleatorio para familias de claves designadas y agrega una garantía sobre la distribución uniforme de los códigos hash.
La definición más estricta, introducida por Wegman y Carter [2] bajo el nombre de "familia hash fuertemente universal ", es la siguiente: una familia de funciones hash es independiente si para cualquier clave distinta y cualquier código hash (no necesariamente distinto) , tenemos:
Esta definición es equivalente a las dos condiciones siguientes:
A menudo resulta inconveniente lograr la probabilidad conjunta perfecta debido a problemas de redondeo. A continuación, [3] se puede definir una familia independiente para satisfacer:
Obsérvese que, incluso si está cerca de 1, ya no son variables aleatorias independientes, lo que suele ser un problema en el análisis de algoritmos aleatorios. Por lo tanto, una alternativa más común para tratar los problemas de redondeo es demostrar que la familia hash está cerca en distancia estadística a una familia -independiente, lo que permite el uso de caja negra de las propiedades de independencia.
La técnica original para construir funciones hash k -independientes, dada por Carter y Wegman, era seleccionar un número primo grande p , elegir k números aleatorios módulo p y usar estos números como los coeficientes de un polinomio de grado k − 1 cuyos valores módulo p se usan como el valor de la función hash. Todos los polinomios del grado dado módulo p son igualmente probables, y cualquier polinomio está determinado de forma única por cualquier k -tupla de pares argumento-valor con argumentos distintos, de lo que se deduce que cualquier k -tupla de argumentos distintos tiene la misma probabilidad de ser mapeada a cualquier k -tupla de valores hash. [2]
En general, el polinomio puede evaluarse en cualquier cuerpo finito . Además de los cuerpos módulo primo, una opción popular es el cuerpo de tamaño , que admite una aritmética rápida de cuerpos finitos en las computadoras modernas. Este fue el enfoque adoptado por Daniel Lemire y Owen Kaser para CLHash. [4]
El hash de tabulación es una técnica para mapear claves a valores hash al particionar cada clave en bytes , usar cada byte como índice en una tabla de números aleatorios (con una tabla diferente para cada posición de byte) y combinar los resultados de estas búsquedas de tabla mediante una operación exclusiva o bit a bit . Por lo tanto, requiere más aleatoriedad en su inicialización que el método polinomial, pero evita operaciones de multiplicación posiblemente lentas. Es independiente de 3 pero no de 4. [5] Las variaciones del hash de tabulación pueden lograr mayores grados de independencia al realizar búsquedas de tabla basadas en combinaciones superpuestas de bits de la clave de entrada, o al aplicar el hash de tabulación simple de manera iterativa. [6] [7]
La noción de k -independencia se puede utilizar para diferenciar entre diferentes resoluciones de colisión en tablas hash, según el nivel de independencia requerido para garantizar un tiempo esperado constante por operación.
Por ejemplo, el encadenamiento de hash requiere un tiempo esperado constante incluso con una familia de funciones hash 2-independientes , porque el tiempo esperado para realizar una búsqueda de una clave dada está limitado por el número esperado de colisiones en las que está involucrada esa clave. Por linealidad de la expectativa, este número esperado es igual a la suma, sobre todas las demás claves en la tabla hash, de la probabilidad de que la clave dada y la otra clave colisionen. Debido a que los términos de esta suma solo involucran eventos probabilísticos que involucran dos claves, la 2-independencia es suficiente para asegurar que esta suma tenga el mismo valor que tendría para una función hash verdaderamente aleatoria. [2]
El hash doble es otro método de hash que requiere un bajo grado de independencia. Es una forma de direccionamiento abierto que utiliza dos funciones hash: una para determinar el inicio de una secuencia de sondeo y la otra para determinar el tamaño del paso entre las posiciones en la secuencia de sondeo. Mientras ambas sean independientes entre sí, este método proporciona un tiempo esperado constante por operación. [8]
Por otra parte, se puede garantizar que el sondeo lineal , una forma más simple de direccionamiento abierto donde el tamaño del paso es siempre uno, funcione en un tiempo esperado constante por operación con una función hash de 5 independientes, [9] y existen funciones hash de 4 independientes para las que se necesita un tiempo logarítmico por operación. [10]
Para el hash Cuckoo, la k-independencia requerida no se conoce a partir de 2021. En 2009 se demostró [11] que la k-independencia es suficiente y se necesita al menos 6-independencia . Otro enfoque es utilizar el hash Tabulation , que no es 6-independiente, pero se demostró en 2012 [12] que tiene otras propiedades suficientes para el hash Cuckoo. Un tercer enfoque de 2014 [13] es modificar ligeramente la tabla hash cuckoo con un llamado stash, que hace posible usar nada más que 2-funciones hash independientes.
Kane , Nelson y David Woodruff mejoraron el algoritmo Flajolet-Martin para el problema de elementos distintos en 2010. [14] Para dar una aproximación a la respuesta correcta, necesitan una función hash independiente .
El algoritmo de boceto Count para la reducción de dimensionalidad requiere dos funciones hash, una 2-independiente y otra 4-independiente .
El algoritmo de Karloff-Zwick para el problema MAX-3SAT se puede implementar con 3 variables aleatorias independientes.
El algoritmo MinHash se puede implementar utilizando una función hash independiente como lo demostró Piotr Indyk en 1999 [15].