bmaj8PCosFLAJjeHaevvvchnJedmg2iujpePOPivI2x2asw0yKa2eA15xvFJMFe82RGIcdlvxyaAPRuDuJhFjbh78BFsnCufJkarwEyKa0azHxccw5qegpcP9yaO0FKoohanxgiAfK1Lqwba51bKtjacbvdjMmcBkiv8kd62sBd98c4twa98sgj3iPh7nkP4
rlaejTPrua1DhBdg0jrIoDBi8fc1GIJAigivIGaxs1OmfPcctNadK3HErvzPLCeDPD8fkMNPCBcIwuoGfEHegOfk9k9pwktslqaBenaati1uNthMiyk9ndpy7gdIz88iot6A09cbNeIMheyjBvbeegL7aGp7mCb91hCxnvgV5abfImrPfLbrbraAsN6loJgh
Ambas cadenas se combinan para bb66000000000000d698000000000000
Al igual que "C, 128 bytes - por: apretar osteo", los bits de orden superior nunca influyen en los bits de orden inferior, esto puede explotarse.
Código
Visual C ++, utiliza operaciones de cadena " inseguras "
#include "stdafx.h"
#include <string>
#include <iostream>
#include <fstream>
long long x, y;
//Original hash function (not used for cracking).
void h(char inp[]){
long long c;
int index = 0;
int len = strlen(inp);
x = 0;
y = 0;
long long p = 0;
for (c = 9; c ; c = (index<len?inp[index++]:-1) + 1) {
for (++p; c--;) {
x = x*'[3QQ' + p;
y ^= c*x;
y ^= x ^= y;
}
}
printf("%016llx%016llx\n", x, y);
}
//Partial hash, takes a string and a starting point in the stream.
//The byte 0x08 must be prepended to a string in order to produce a full legal hash.
void hp(char inp[],long long p){
long long c;
int index = 0;
int len = strlen(inp);
x = 0;
y = 0;
for (index = 0; index<len; index++) {
c = inp[index] + 1;
for (++p; c--;) {
x = x*'[3QQ' + p;
y ^= c*x;
y ^= x ^= y;
}
}
}
//Reverse partial hash, backtracks the inner state.
void hprev(char inp[], long long p){
long long c;
long long clim;
int index = 0;
int len = strlen(inp);
p += len + 1;
x = 0;
y = 0;
for (index = len-1; index>=0; index--) {
clim = inp[index] + 1;
c = 0;
for (--p; c<clim;c++) {
y ^= x;
x ^= y;
y ^= c*x;
x -= p;
x = x * 17372755581419296689;
//The multiplicative inverse of 1530089809 mod 2^64.
}
}
}
const int rows = 163840;
const int maprows = 524288;
//Store for intermediate input strings, row 0 contains 64 columns with 3-char strings,
//row 1 contain 32 columns with 6-char strings and so forth, the final strings will
//contain one string from each column, in order.
char store[7][rows][512];
//Storage for a hashmap, used for matching n strings with n string in O(n) time.
char map[maprows][512];
int _tmain(int argc, _TCHAR* argv[])
{
char alpha[] = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int row;
int col;
int layer;
int a=0, b=0, c=0;
int colzero;
//Produce some starting strings.
for (row = 0; row < rows; row++){
//All column 0 strings begin with 0x08 in order to imitate the hash.
store[0][row][0] = 8;
colzero = 1;
for (col = 0; col < 64; col++){
store[0][row][col * 8 + colzero] = alpha[a];
store[0][row][col * 8 + colzero + 1] = alpha[b];
store[0][row][col * 8 + colzero + 2] = alpha[c];
store[0][row][col * 8 + colzero + 3] = 0;
colzero = 0;
}
a++;
if (a >= 52){
b++;
a = 0;
if (b >= 52){
c++;
b = 0;
}
}
}
//Layer for layer, column for column, build strings that preserve successively
//more zero bits. Forward calculated partial hashes are matched with backwards
//calculated partial hashes.
for (layer = 1; layer < 7; layer++){
int slayer = layer - 1;
int swidth = 1 << (slayer + 3);
int width = 1 << (layer + 3);
int slen = 3 << slayer;
int len = 3 << layer;
int colnum;
int layershift=slayer*8;
for (col = 0,colnum=0; col < 512; col+=width,colnum++){
printf("Layer: %i, column: %i\n",layer,colnum);
memset(map, 0, sizeof map);
int col2 = col + swidth;
for (row = 0; row < rows; row++){
hprev(store[slayer][row] + col2, 1 + slen*(1 + colnum * 2));
x = (x >> layershift) & 255;
y = (y >> layershift) & 255;
int index = (x << 3) | (y << 11);
for (a = 0; a < 8; a++){
if (map[index + a][0] == 0){
strcpy_s(map[index + a], store[slayer][row] + col2);
break;
}
}
}
int destrow = 0;
for (row = 0; row < rows && destrow < rows; row++){
hp(store[slayer][row] + col, !!colnum + slen*(colnum * 2));
x = (x >> layershift) & 255;
y = (y >> layershift) & 255;
int index = (x << 3) | (y << 11);
for (a = 0; a < 8 && destrow < rows; a++){
if (map[index + a][0]){
strcpy(store[layer][destrow] + col, store[slayer][row] + col);
strcat(store[layer][destrow] + col, map[index + a]);
destrow++;
}
}
}
}
}
memset(map, 0, sizeof map);
char temp[1000];
std::ofstream myfile;
myfile.open("hashout.txt");
for (row = 0; row < rows; row++){
hp(store[6][row], 0);
sprintf(temp, "%016llx%016llx", x, y);
myfile << store[6][row] <<" " << temp << "\n";
}
myfile << "\n";
//The final hash set has 96 of 128 output bits set to 0, I could have gone all
//the way, but this is enough to find a collision via the birthday paradox.
for (row = 0; row < rows; row++){
hp(store[6][row], 0);
long long xc = x;
long long yc = y;
int pos = (xc >> 45 | ((yc >> 48) & 7)) & (maprows-1);
while (map[pos][0]!=0){
hp(map[pos], 0);
if (x == xc && y == yc){
myfile << store[6][row] << "\n" << map[pos] << "\n";
sprintf(temp,"%016llx%016llx", x, y);
myfile << temp << "\n\n";
}
pos = (pos + 1) % maprows;
}
strcpy_s(map[pos], store[6][row]);
}
myfile.close();
printf("done");
getchar();
return 0;
}
Python, 109 bytes por Sp3000
Tenga en cuenta que Martin se rompió primero, así que no estoy seguro de si esto merece puntos. Por otro lado, hice un ataque de preimagen en lugar de una simple colisión, un resultado mucho más fuerte. Esto significa que puede darle un valor hash arbitrario, y construirá una entrada que genere ese valor hash.
Y para demostrar que funciona:
Y para dar un conjunto particular de números que colisionan:
fuente
Python, 109 bytes por Sp3000
y
ambos rinden
El algoritmo divide la entrada en fragmentos de 128 bits y modifica repetidamente el hash (sembrado a
42
) con cada fragmento, antes de realizar un hash adicional al final. Para encontrar una colisión, nuestro objetivo es encontrar dos números que den el mismo resultado después de ejecutar el siguiente pseudocódigo en cada fragmento:Dado que el hash se toma mod 2 128 , queremos buscar números que cambien todas las cosas interesantes fuera de este rango de bits. Pero el hash está sembrado, por
42
lo que tiene algunos bits no tan significativos establecidos para comenzar:Mi idea era deshacerme de esas partes al agregar el primer fragmento. Entonces intentemos 2 128 -42:
Eso es bastante simple, así que tratemos de usarlo como uno de los dos números. (De hecho, el primer número de la colisión que utilicé es 2 128 -42.
Ahora, ¿cómo encontramos otro número con el mismo resultado? Bueno, después de una iteración, el hash ya no está
42
, pero2**122
como acabamos de mostrar. Ahora, agregando un segundo fragmento a nuestro número de entrada, podemos ejecutar otra iteración. Podemos elegir el segundo fragmento con el mismo argumento que este, es decir, queremos 2 128 -2 122 . Luego, el resultado intermedio despuéshash += chunk
será idéntico y terminaremos con el mismo resultado al final.Entonces podemos calcular los dos números de la colisión:
Podemos generar fácilmente muchas más colisiones como esta.
fuente
Mathematica, 89 bytes por LegionMammal978
y
Ambos rinden
0
.El principio de este policía es desarrollar un autómata celular binario "aleatorio" a partir de una condición inicial "aleatoria" para un número "aleatorio" de pasos, y luego interpretar las primeras 128 celdas del resultado como un número entero.
El problema es que la regla se determina simplemente por
Mod[#^2,256]
, de modo que cualquier múltiplo de 16 da la regla0
, que es la regla trivial donde todas las celdas son siempre cero. Si la entrada no es divisible por 99, evolucionaremos al menos 1 paso, por lo que la salida siempre es cero. Entonces, dos múltiplos que no son múltiplos de 99 definitivamente chocan. Sin embargo, la entrada0
también da 0 (a pesar de no usar nunca la regla), porque la condición inicial es solo la representación binaria de la entrada (que es todo ceros en este caso).Como comentario aparte, podemos encontrar otras colisiones que son completamente independientes de la regla. Como se señaló anteriormente, cualquier múltiplo de 99 significa que el autómata celular no ha evolucionado en absoluto, por lo que el resultado es simplemente los primeros 128 bits (más significativos) de la condición inicial ... que es solo el número de entrada. Entonces, si tomamos dos múltiplos que no difieren en los primeros 128 bits (rellenados a la derecha con ceros), también tenemos una colisión. El ejemplo más sencillo de esto es
M = 99
,N = 99*2 = 198
.fuente
J, 39 bytes
El primer número es:
Es decir,
10000000
repetido 64 veces. El segundo número es ese más uno, es decirAmbos rinden
Explicación
Comencemos con
x := H 10000000 = 146018215378200688979555343618839610915
, yy := 2^128
. En lugar de encontrara, b
tal cosaa == b mod y
, buscaremosa, b
tal cosax^a == x^b mod y
, haciendo uso de las torres de poder en el algoritmo.Pero debe haber algo
k
asíx^k == 1 mod y
, ya quex, y
son coprimos, y para esok
debemos tenera == b mod k
. Entonces podemos encontrar el logaritmo discreto de 1 mody
, y para el primer paso obtenemosAsí que ahora queremos encontrar dos números
a, b
tales quea == b mod k
. Para hacer esto, establecemosy
serk
y tratamos de encontrara, b
eso dex^a == x^b mod y
nuevo. Usando la misma lógica, tomamos el logaritmo discreto nuevamente y obtenemosRepetimos esto hasta llegar a un pequeño
y
, en cuyo punto es trivial encontrar dos números que tengan el mismo móduloy
. Después de 63 iteracionesy = 4
, en ese punto básicamente funcionan dos números.Aquí está el código de Mathematica para generar la cadena de registro discreta:
Esto da el siguiente resultado .
fuente
2^(2^30)
límite, de ahí el cheque.Pyth, 8 bytes por FryAmTheEggman
y
La precisión de coma flotante no es lo suficientemente grande para esto.
fuente
437409784163148
para los dos. Me pregunto por qué hay una diferencia ...437409784163148
y37409784163148
así que supongo que acaba de perder el último dígito, por alguna razón, pero ... 99 997 da la misma respuesta que 999 ... 98.CJam, 44 bytes,
usuariojimmy23013Los números son demasiado grandes para publicar, así que aquí están en Pastebin: num 1 , num 2 .
El primer número son
600^2 = 360000
unos. El segundo número es el mismo, excepto por los siguientes cambios:Ambos hash a
271088937720654725553339294593617693056
.Explicación
Echemos un vistazo a la primera mitad del código:
Entonces, si podemos encontrar dos números de entrada para que las sumas
S[i][j]*13^i*19^j
sean del mismo módulo16^20
tanto para la matriz inicial de 600 anchos como para la matriz comprimida, entonces hemos terminado.Para facilitar un poco las cosas, consideraremos solo
600^2 = 360000
números de entrada de dígitos, de modo que la matriz de 600 de ancho sea solo un cuadrado de 600 por 600 de dígitos. Esto hace que las cosas sean más fáciles de visualizar y es válido desde entonces10^360000 ~ 2^(2^20.19) < 2^(2^30)
. Para simplificar aún más las cosas, solo consideraremos las cadenas de entrada cuyo cuadrado de dígitos es simétrico a lo largo de la diagonal principal, de modo que la matriz original y la matriz comprimida sean las mismas. Esto también nos permite ignorar la inversión inicial de la cadena y la numeración del índice de derecha a izquierda, que se cancelan mutuamente.Para comenzar, podemos tomar el primer número como
360000
unos. Para obtener el segundo número, queremos modificar esto cambiando algunos de los dígitos para que las sumas sean del mismo módulo16^20
, mientras se preserva la simetría del cuadrado del dígito. Logramos esto al encontrar una lista de triples(i, j, k)
para quedonde
1 <= k <= 8
es la cantidad para aumentar el dígito 1 (es decir, cambiar a un dígito de 2 a 9; podríamos haber incluido 0 pero no lo necesitamos) y0 <= i < j < 600
son pares de índices.Una vez que tenemos los
(i, j, k)
trillizos, que cambiar los dígitos en(i, j)
y(j, i)
para1+k
conseguir el segundo número. Los trillizos se encontraron usando un algoritmo de retroceso codicioso, y para el segundo número sobre el cuadrado del dígito se ve así:Por ejemplo,
(i, j, k) = (0, 1, 7)
corresponde a cambiar los dígitos(0, 1)
(posición600*0 + 1 = 1
) y(1, 0)
(posición600*1 + 0 = 600
) a1 + 7 = 8
.Aquí está el backtracker en Python 3, aunque una inspección más cercana reveló que tuvimos bastante suerte, ya que en realidad no hubo retroceso:
Como beneficio adicional, aquí hay un puerto no tan eficiente del hash en Python 3. Era inútil.
fuente
PHP 4.1, 66 bytes por Ismael Miguel
Encontrado usando hashing iterado simple, comenzando desde 1:
fuente
hash(hash(hash(...(hash(1)...)))
). La primera cadena convergió en un bucle casi al instante. Ni siquiera necesité sacar mi cracker de hash multiproceso.Python 3 (216) por Sp3000
Mis mensajes son
Usé este código de Python 2 para generarlos:
El gran módulo fue producto de dos primos
a
yb
. Supongo que la esperanza era que sería NP-imposible para nosotros factorizar el semiprime, pero supongo que 128 bits es demasiado pequeño ya que alguna página web me dio la respuesta de inmediato.El módulo del grupo multiplicativo
ab
tendrá orden (a - 1) (b - 1), lo que significa que si elevamos cualquier número a esa potencia, tendrá que resultar en 0 o (generalmente) 1. Así que puse 1 bits en lugares que resultaron en 2 (a-1) (b-1) se multiplica en el hash. Entonces, el otro mensaje es básicamente 0, pero configuré otro bit en cada número para que las longitudes sean las mismas.Creo que hubiera sido más molesto si el hash estuviera al cuadrado en cada bit, en lugar de solo después de usar todos los números primos. Entonces no habría sido tan simple construir exponentes arbitrarios para ellos.
fuente
C, 128 bytes - por: apremiante ossifrage
Las siguientes dos cadenas tienen hash a todos los ceros:
La función hash está construida para que los bits de orden superior nunca influyan en los bits de orden inferior, por lo tanto, puedo generar una colección de cadenas donde todos los
x
bits de orden inferior son cero, luego puedo intentar combinaciones concatenadas de estas cadenas para encontrar algo más los bits más bajos son cero, etc. Estoy bastante seguro de que hay más formas de romper esto, y también formas que producen cadenas significativamente más cortas, pero de esta manera evité hacer muchas matemáticas.fuente
0x0000000a0000000a0000000a0000000a
con mi sistema, pero eso sigue siendo bastante sorprendente. (echo -ne '\x0a' |./hash
también da el mismo resultado.)Python 3, 118 bytes
y
(es decir: 9E400 y 9E4000)
Ambos producen
Excavando un poco más profundo, parece que cualquier número entero seguido de k dígitos repetidos de tal manera que k> 128 y (k% 4 == 0) devolverá el mismo hash. Por ejemplo,
H("1"+"1"*32*4)
yH("1"+"1"*33*4)
son ambos13493430891393332689861502800964084413
. Hmmm, 128 ...fuente
Python 2, 161 bytes, por Puzzled
y
Ambos tienen la salida:
Los números son 2 ^ 128 y 2 ^ 128 + (3 * 5 * 7 * 11 * 13 * 17) ^ 2 * 19 * 2 ^ 32.
fuente
Java, 299 bytes por SuperJedi224
Pastebin para
M
. En binario,M
tiene 655351
s, seguido de 20
s.Pastebin para
N
. En binario,N
tiene 218451
s, seguido de 1747660
s.Ambos rinden
0
.Tenga en cuenta que la base del algoritmo es
i.bitCount()*i.bitLength()+1
y, en última instancia, llevamos el resultado al poder dei
y lo tomamos mod 2 128 . Entonces, la idea era encontrar dosi
que sean divisibles por cuatro, pero donde la primera expresión dé 2 32 . Eso se hizo fácilmente factorizando 2 32 -1 y seleccionando dos factores para el recuento de 1s y el ancho total de bits del número.Editar: En realidad, hay un poco más de por qué
M
produce cero, pero podemos encontrar fácilmente más números que producen cero debido a mi explicación utilizando otros factores de 2 32 -1, de modo que hay al menos 64 ceros al final.fuente
C, 134 bytes (por Barteks2x)
y
tanto hash para
¡porque el algoritmo solo divide el último dígito!
fuente
C, 87 bytes
Encontrado usando mi colisión bruteforcer.
fuente
473E0B6ED5AF2B92 7EC2BC9B5E9F5645 -> 0000000000000000 0EAC34C8A9F94389
después de 3525078917 llamadas de función hash yreal 14m24.970s user 48m42.410s
hora.Python 2, 115 bytes, por ossifrage aprensivo
y
El valor hash no tuvo nada que ver con el orden de los bloques.
fuente
Python 2.x, 139 bytes por Puzzled
H(2)
y
H(128)
ambos regresan
16645614427504350476847004633262883518
.fuente
C ++, 239 bytes por SpelingMistake
Usando el programa "principal" proporcionado, las siguientes dos entradas producen el mismo hash:
y
Los primeros 8 bytes de entrada nunca se procesan , debido a este error en el código:
porque se
--i
evalúa como falso cuandoi==1
,q[0]
(los primeros 8 bytes:I
es anint64
). Reemplazar la condición de bucle confor(I i=n;i--;)
habría solucionado esto.fuente
Ruby, 90 Bytes, por MegaTom
y
que son 2 y 11 seguidos de 40 bytes cero. Entonces ambos tienen 41 bytes. El valor hash se agrega por la longitud de entrada para cada byte, y luego se invierte en decimal. Una longitud de entrada que termina con
1
puede asegurarse de que el valor hash termine con0
bastante rapidez. Luego, invertirlo reduce la longitud del valor hash en 1.Ambos tienen el valor hash
259
.fuente
C # - 393 bytes - por: Presa Logan
70776e65642062792031333337206861786f72
y70776e65642062792031333337206861786f7200
ambos hash a18E1C8E645F1BBD1
.fuente