bmaj8PCosFLAJjeHaevvvchnJedmg2iujpePOPivI2x2asw0yKa2eA15xvFJMFe82RGIcdlvxyaAPRuDuJhFjbh78BFsnCufJkarwEyKa0azHxccw5qegpcP9yaO0FKoohanxgiAfK1Lqwba51bKtjacbvdjMmcBkiv8kd62sBd98c4twa98sgj3iPh7nkP4
rlaejTPrua1DhBdg0jrIoDBi8fc1GIJAigivIGaxs1OmfPcctNadK3HErvzPLCeDPD8fkMNPCBcIwuoGfEHegOfk9k9pwktslqaBenaati1uNthMiyk9ndpy7gdIz88iot6A09cbNeIMheyjBvbeegL7aGp7mCb91hCxnvgV5abfImrPfLbrbraAsN6loJgh
Ambas as strings para bb66000000000000d698000000000000
Assim como "C, 128 bytes - por: ossifrage squeamish", os bits de ordem superior nunca influenciam os bits de ordem inferior; isso pode ser explorado.
Código
Visual C ++, usa operações de seqüência de caracteres " 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
Observe que Martin rachou primeiro, então não tenho certeza se isso merece pontos. Por outro lado, fiz um ataque de pré-imagem em vez de uma simples colisão - um resultado muito mais forte. Isso significa que você pode atribuir um valor de hash arbitrário e criará uma entrada que gera esse valor de hash.
E para mostrar que funciona:
E para fornecer um conjunto específico de números que colidem:
fonte
Python, 109 bytes por Sp3000
e
ambos produzem
O algoritmo divide a entrada em pedaços de 128 bits e modifica repetidamente o hash (semeado para
42
) com cada pedaço, antes de fazer um hash extra no final. Para encontrar uma colisão, nosso objetivo é encontrar dois números que produzam o mesmo resultado depois de executar o seguinte pseudo-código em cada parte:Como o hash é obtido no mod 2 128 , queremos procurar números que mudem todas as coisas interessantes fora desse intervalo de bits. Mas o hash é semeado para
42
ter alguns bits não tão significativos definidos para começar:Minha idéia era livrar-se desses bits ao adicionar o primeiro pedaço. Então, vamos tentar 2 128 -42:
Isso é bastante simples, então vamos tentar usá-lo como um dos dois números. (Com efeito, o primeiro número da colisão I utilizada é de 2 128 -42.
Agora, como encontramos outro número com o mesmo resultado? Bem, após uma iteração, o hash não é
42
mais, mas2**122
como acabamos de mostrar. Agora, adicionando um segundo pedaço ao nosso número de entrada, podemos executar outra iteração. Podemos escolher o segundo pedaço pelo mesmo argumento que este, ou seja, queremos 2 128 -2 122 . Então o resultado intermediário depoishash += chunk
será idêntico e terminamos com o mesmo resultado no final.Assim, podemos calcular os dois números da colisão:
Podemos facilmente gerar muito mais colisões como essa.
fonte
Mathematica, 89 bytes por LegionMammal978
e
Ambos produzem
0
.O princípio desse policial é desenvolver um autômato celular 1-D binário "aleatório" a partir de uma condição inicial "aleatória" para um número "aleatório" de etapas e, em seguida, interpretar as primeiras 128 células do resultado como um número inteiro.
O problema é que a regra é determinada simplesmente por
Mod[#^2,256]
, de modo que qualquer múltiplo de 16 dê a regra0
, que é a regra trivial em que todas as células são sempre zero. Se a entrada não for divisível por 99, evoluiremos pelo menos 1 passo, para que a saída seja sempre zero. Portanto, quaisquer dois múltiplos que não sejam múltiplos de 99 definitivamente colidem. No entanto, a entrada0
também fornece 0 (apesar de nunca usar a regra), porque a condição inicial é apenas a representação binária da entrada (que é todos os zeros neste caso).Como um aparte, podemos encontrar outras colisões que são completamente independentes da regra. Como observado acima, qualquer múltiplo de 99 significa que o autômato celular não evoluiu de modo algum, então o resultado são simplesmente os primeiros (mais significativos) 128 bits da condição inicial ... que é apenas o número de entrada. Portanto, se pegarmos dois múltiplos que não diferem nos primeiros 128 bits (preenchidos à direita com zeros), também teremos uma colisão. O exemplo mais simples disso é
M = 99
,N = 99*2 = 198
.fonte
J, 39 bytes
O primeiro número é:
Ou seja,
10000000
repetido 64 vezes. O segundo número é aquele mais um, ou seja,Ambos produzem
Explicação
Vamos começar com
x := H 10000000 = 146018215378200688979555343618839610915
, ey := 2^128
. Em vez de acharmosa, b
issoa == b mod y
, procuraremosa, b
quex^a == x^b mod y
, usando as torres de energia do algoritmo.Mas deve haver alguns
k
quex^k == 1 mod y
, desde quex, y
são coprimes, e para issok
devemos tera == b mod k
. Assim, podemos encontrar o logaritmo discreto de 1 mody
e, na primeira etapa, obtemosEntão agora queremos encontrar dois números
a, b
como essea == b mod k
. Para fazer isso, definimos oy
que ék
e tentamos encontrar de novoa, b
issox^a == x^b mod y
. Usando a mesma lógica, pegamos o logaritmo discreto novamente e obtemosRepetimos isso até chegarmos a um valor pequeno
y
, e nesse ponto é trivial encontrar dois números que misturam com o mesmo móduloy
. Após 63 iteraçõesy = 4
, nesse ponto basicamente dois números funcionam.Aqui está o código do Mathematica para gerar a cadeia de log discreta:
Isso fornece a seguinte saída .
fonte
2^(2^30)
limite, daí o cheque.Pyth, 8 bytes por FryAmTheEggman
e
A precisão do ponto flutuante não é grande o suficiente para isso.
fonte
437409784163148
pelos dois. Eu me pergunto por que há uma diferença ...437409784163148
e37409784163148
acho que acabou de perder o último dígito por algum motivo, mas 99 ... 997 dá a mesma resposta que 999 ... 98.CJam, 44 bytes,
usuáriojimmy23013Os números são grandes demais para serem publicados, então aqui estão eles no Pastebin: num 1 , num 2 .
O primeiro número é um
600^2 = 360000
. O segundo número é o mesmo, exceto para as seguintes alterações:Ambos hash para
271088937720654725553339294593617693056
.Explicação
Vamos dar uma olhada na primeira metade do código:
Portanto, se pudermos encontrar dois números de entrada para que as somas de
S[i][j]*13^i*19^j
sejam o mesmo módulo16^20
para a matriz inicial de 600 e a matriz compactada, então terminamos.Para tornar as coisas um pouco mais fáceis, consideraremos apenas
600^2 = 360000
números de entrada com dois dígitos, para que a matriz de 600 caracteres tenha apenas 600 por 600 quadrados de dígitos. Isso facilita a visualização das coisas e é válido desde então10^360000 ~ 2^(2^20.19) < 2^(2^30)
. Para simplificar ainda mais as coisas, consideraremos apenas as cadeias de entrada cujo quadrado de dígitos é simétrico ao longo da diagonal principal, para que a matriz original e a matriz compactada sejam iguais. Isso também nos permite ignorar a reversão inicial da string e a numeração do índice da direita para a esquerda, que se cancelam.Para começar, podemos considerar o primeiro número como um
360000
. Para obter o segundo número, queremos modificar isso alterando alguns dígitos, para que as somas sejam o mesmo módulo16^20
, preservando a simetria do quadrado do dígito. Conseguimos isso encontrando uma lista de triplos(i, j, k)
para queonde
1 <= k <= 8
é o valor para aumentar o dígito 1 (alterando para um dígito de 2 para 9 - poderíamos ter incluído 0, mas não precisamos dele) e0 <= i < j < 600
somos pares de índices.Uma vez que temos os
(i, j, k)
trigêmeos, mudamos os dígitos no(i, j)
e(j, i)
para1+k
obter o segundo número. Os trigêmeos foram encontrados usando um algoritmo ganancioso de retorno, e para o segundo número acima do dígito quadrado se parece com:Por exemplo,
(i, j, k) = (0, 1, 7)
corresponde à alteração dos dígitos(0, 1)
(posição600*0 + 1 = 1
) e(1, 0)
(posição600*1 + 0 = 600
) para1 + 7 = 8
.Aqui está o backtracker no Python 3, embora uma inspeção mais detalhada tenha revelado que tivemos muita sorte, pois nenhum backtracking realmente aconteceu:
Para um bônus, aqui está uma porta não tão eficiente do hash no Python 3. Era inútil.
fonte
PHP 4.1, 66 bytes por Ismael Miguel
Encontrado usando hash iterado simples, começando em 1:
fonte
hash(hash(hash(...(hash(1)...)))
). A primeira cadeia convergiu em um loop quase instantaneamente. Eu nem precisei abrir meu hash cracker multithread.Python 3 (216) por Sp3000
Minhas mensagens são
Eu usei esse código Python 2 para gerá-los:
O grande módulo era um produto de dois primos
a
eb
. Acho que a esperança era que seria impossível para o NP fatorar o semiprime, mas acho que 128 bits é muito pequeno, já que algumas páginas da web me deram a resposta imediatamente.O módulo do grupo multiplicativo
ab
terá ordem (a - 1) (b - 1), o que significa que, se elevarmos qualquer número a esse poder, ele terá que resultar em 0 ou (geralmente) 1. Então, eu coloquei 1 bits em locais que resultaram em 2 (a-1) (b-1) sendo multiplicado no hash. Em seguida, a outra mensagem é basicamente 0, mas defino outro bit em cada número para tornar os comprimentos iguais.Eu acho que teria sido mais irritante se o hash ao quadrado fosse melhor do que depois de usar todos os números primos. Então não seria tão simples construir expoentes arbitrários para eles.
fonte
C, 128 bytes - por: ossifrage squeamish
As duas seqüências a seguir ambos hash para todos os zeros:
A função hash é criada para que os bits de ordem superior nunca influenciem os bits de ordem inferior; portanto, eu posso gerar uma coleção de strings em que todos os
x
bits de ordem inferior são zero; em seguida, posso tentar combinações concatenadas dessas strings para encontrar algumas onde mais os bits mais baixos são zero etc. Tenho certeza de que há mais maneiras de quebrar isso, e também maneiras que produzem seqüências significativamente mais curtas, mas dessa maneira evitei fazer muitas contas.fonte
0x0000000a0000000a0000000a0000000a
no meu sistema, mas isso ainda é incrível. (echo -ne '\x0a' |./hash
Também dá o mesmo resultado.)Python 3, 118 bytes
e
(ou seja: 9E400 e 9E4000)
Ambos produzem
Indo um pouco mais fundo, parece que qualquer número inteiro seguido por k dígitos repetidos, de forma que k> 128 e (k% 4 == 0) retornem o mesmo hash. Por exemplo,
H("1"+"1"*32*4)
eH("1"+"1"*33*4)
são ambos13493430891393332689861502800964084413
. Hmmm, 128 ...fonte
Python 2, 161 bytes, por Intrigado
e
Ambos têm a saída:
Os números são 2 ^ 128 e 2 ^ 128 + (3 * 5 * 7 * 11 * 13 * 17) ^ 2 * 19 * 2 ^ 32.
fonte
Java, 299 bytes por SuperJedi224
Pastebin for
M
. Em binário,M
possui 655351
s, seguidos por 20
s.Pastebin for
N
. Em binário,N
possui 218451
s, seguido por 1747660
s.Ambos produzem
0
.Observe que a base do algoritmo é
i.bitCount()*i.bitLength()+1
e, finalmente, levamos o resultado ao poderi
e o mod 2 128 . Portanto, a idéia era apenas encontrar doisi
que são divisíveis por quatro, mas onde a primeira expressão dá 2 32 . Isso foi feito facilmente, fatorando 2 32 -1 e escolhendo dois fatores para a contagem de 1s e a largura total de bits do número.Edit: Na verdade, há um pouco mais sobre o porquê de
M
produzir zero, mas podemos facilmente encontrar mais números que produzem zero por causa da minha explicação, usando outros fatores de 2 32 -1, de modo que haja pelo menos 64 zeros no final.fonte
C, 134 bytes (por Barteks2x)
e
ambos hash para
porque o algoritmo hashes apenas o último dígito!
fonte
C, 87 bytes
Encontrado usando meu bruteforcer de colisão.
fonte
473E0B6ED5AF2B92 7EC2BC9B5E9F5645 -> 0000000000000000 0EAC34C8A9F94389
Foi encontrada outra colisão: após 3525078917 chamadas ereal 14m24.970s user 48m42.410s
tempo de função hash .Python 2, 115 bytes, por ossifrage melindroso
e
O valor do hash não tinha nada a ver com a ordem dos blocos.
fonte
Python 2.x, 139 bytes por Intrigado
H(2)
e
H(128)
ambos retornam
16645614427504350476847004633262883518
.fonte
C ++, 239 bytes por SpelingMistake
Usando o programa "principal" fornecido, as duas entradas a seguir produzem o mesmo hash:
e
Os primeiros 8 bytes de entrada nunca são processados , devido a este erro no código:
porque
--i
avalia como false quandoi==1
,q[0]
(os primeiros 8 bytes:I
é umint64
). Substituir a condição do loop porfor(I i=n;i--;)
teria corrigido isso.fonte
Ruby, 90 bytes, da MegaTom
e
que são 2 e 11 seguidos por 40 bytes zero. Então, ambos têm 41 bytes. O valor do hash é adicionado pelo comprimento da entrada para cada byte e, em seguida, é revertido em decimal. Um comprimento de entrada que termina com
1
pode garantir que o valor do hash termine0
rapidamente. A reversão reduz o comprimento do valor do hash em 1.Ambos têm o valor de hash
259
.fonte
C # - 393 bytes - por: Logan Dam
70776e65642062792031333337206861786f72
e70776e65642062792031333337206861786f7200
ambos hash para18E1C8E645F1BBD1
.fonte