bmaj8PCosFLAJjeHaevvvchnJedmg2iujpePOPivI2x2asw0yKa2eA15xvFJMFe82RGIcdlvxyaAPRuDuJhFjbh78BFsnCufJkarwEyKa0azHxccw5qegpcP9yaO0FKoohanxgiAfK1Lqwba51bKtjacbvdjMmcBkiv8kd62sBd98c4twa98sgj3iPh7nkP4
rlaejTPrua1DhBdg0jrIoDBi8fc1GIJAigivIGaxs1OmfPcctNadK3HErvzPLCeDPD8fkMNPCBcIwuoGfEHegOfk9k9pwktslqaBenaati1uNthMiyk9ndpy7gdIz88iot6A09cbNeIMheyjBvbeegL7aGp7mCb91hCxnvgV5abfImrPfLbrbraAsN6loJgh
Oba ciągi mają skrót bb66000000000000d698000000000000
Podobnie jak „C, 128 bajtów - przez: piskliwy ossifrage”, bity wyższego rzędu nigdy nie wpływają na bity niższego rzędu, można to wykorzystać.
Kod
Visual C ++ używa „ niebezpiecznych ” operacji na łańcuchach
#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 bajtów przez Sp3000
Zauważ, że Martin pękł jako pierwszy, więc nie jestem pewien, czy to zasługuje na punkty. Z drugiej strony zrobiłem atak przedobrazowy zamiast zwykłej kolizji - znacznie silniejszy wynik. Oznacza to, że możesz nadać mu dowolną wartość skrótu i skonstruuje dane wejściowe, które wygenerują tę wartość skrótu.
I aby pokazać, że to działa:
I aby podać określony zestaw liczb, które kolidują:
źródło
Python, 109 bajtów przez Sp3000
i
oba dają
Algorytm dzieli dane wejściowe na fragmenty 128 bitów i wielokrotnie modyfikuje skrót (zaszczepiony do
42
) z każdym fragmentem, zanim na końcu dokona dodatkowego haszowania. Aby znaleźć kolizję, naszym celem jest znalezienie dwóch liczb, które dają taki sam wynik po uruchomieniu następującego pseudo kodu na każdej porcji:Ponieważ hash jest pobierany mod 2 128 , chcemy szukać liczb, które przesuwają wszystkie interesujące rzeczy poza ten zakres bitów. Ale hash jest zaszczepiony,
42
więc na początku ma kilka mniej znaczących bitów:Moim pomysłem było pozbycie się tych fragmentów podczas dodawania pierwszego fragmentu. Więc spróbujmy 2 128 -42:
To dość proste, więc spróbujmy użyć tego jako jednej z dwóch liczb. (Rzeczywiście, pierwszy numer kolizji, którego użyłem, to 2 128 -42.
Jak znaleźć kolejny numer z takim samym wynikiem? Po jednej iteracji hash już nie jest
42
, ale2**122
jak właśnie pokazaliśmy. Teraz, dodając drugi fragment do naszego numeru wejściowego, możemy uruchomić kolejną iterację. Możemy wybrać drugi fragment za pomocą tego samego argumentu, co ten, tzn. Chcemy 2 128 -2 122 . Następnie wynik pośrednihash += chunk
będzie identyczny i na końcu otrzymamy ten sam wynik.Możemy więc obliczyć dwie liczby kolizji:
Możemy łatwo wygenerować o wiele więcej takich kolizji.
źródło
Mathematica, 89 bajtów autorstwa LegionMammal978
i
Oba zbiory
0
.Zasadą tego policjanta jest ewolucja „losowego” binarnego automatu komórkowego 1-D z „losowego” stanu początkowego dla „losowej” liczby kroków, a następnie interpretacja pierwszych 128 komórek wyniku jako liczby całkowitej.
Problem polega na tym, że reguła jest określana po prostu przez
Mod[#^2,256]
, że dowolna wielokrotność 16 daje regułę0
, która jest banalną regułą, w której wszystkie komórki są zawsze zerowe. Jeśli dane wejściowe nie są podzielne przez 99, będziemy rozwijać co najmniej 1 krok, więc wynik zawsze wynosi zero. Zatem dowolne dwa wielokrotności, które nie są wielokrotnościami 99, zdecydowanie się zderzają. Jednak wejście daje0
również 0 (mimo że nigdy nie używa reguły), ponieważ warunkiem początkowym jest tylko binarna reprezentacja wejścia (w tym przypadku wszystkie zera).Poza tym możemy znaleźć inne kolizje, które są całkowicie niezależne od reguły. Jak wspomniano powyżej, dowolna wielokrotność 99 oznacza, że automat komórkowy wcale się nie rozwinął, więc wynikiem są po prostu pierwsze (najbardziej znaczące) 128 bitów stanu początkowego ... który sam jest tylko liczbą wejściową. Jeśli więc weźmiemy dwa wielokrotności, które nie różnią się w pierwszych 128 bitach (wypełnione zerami po prawej stronie), otrzymamy również kolizję. Najprostszym przykładem jest to
M = 99
,N = 99*2 = 198
.źródło
J, 39 bajtów
Pierwszy numer to:
To znaczy
10000000
powtórzone 64 razy. Druga liczba to ta plus jeden, tjOba zbiory
Wyjaśnienie
Zacznijmy od
x := H 10000000 = 146018215378200688979555343618839610915
iy := 2^128
. Zamiast znajdowaća, b
takiea == b mod y
, będziemy szukaća, b
takichx^a == x^b mod y
, wykorzystując wieże mocy w algorytmie.Ale musi być jakiś
k
taki, żex^k == 1 mod y
, ponieważx, y
są względnie pierwsze, a do tegok
musimy mieća == b mod k
. Możemy więc znaleźć dyskretny logarytm 1 mody
, a na pierwszy krok dostajemyTeraz chcemy znaleźć dwie
a, b
takie liczbya == b mod k
. Aby to zrobić, postanowiliśmyy
byćk
i staramy się znaleźća, b
takiex^a == x^b mod y
ponownie. Używając tej samej logiki, bierzemy logarytm dyskretny ponownie i otrzymujemyPowtarzamy to, dopóki nie dojdziemy do małego
y
, w którym to momencie znalezienie dwóch liczb, które mają tę samą modulo, jest banalney
. Po 63 iteracjachy = 4
, w tym momencie w zasadzie działają dowolne dwie liczby.Oto kod Mathematica do generowania dyskretnego łańcucha dziennika:
Daje to następujący wynik .
źródło
2^(2^30)
limitu, stąd czek.Pyth, 8 bajtów FryAmTheEggman
i
Precyzja zmiennoprzecinkowa nie jest na to wystarczająco duża.
źródło
437409784163148
za oba. Zastanawiam się, dlaczego jest różnica ...437409784163148
i37409784163148
tak myślę, że to właśnie stracił ostatnią cyfrę z jakiegoś powodu, ale 99 ... 997 daje tę samą odpowiedź jak 999 ... 98.CJam, 44 bajty,
użytkownikjimmy23013Liczby są zbyt duże, aby je opublikować, więc tutaj są na Pastebin: num 1 , num 2 .
Pierwsza liczba to
600^2 = 360000
jedynki. Drugi numer jest taki sam, z wyjątkiem następujących zmian:Oba hash do
271088937720654725553339294593617693056
.Wyjaśnienie
Rzućmy okiem na pierwszą połowę kodu:
Jeśli więc możemy znaleźć dwie liczby wejściowe, aby sumy
S[i][j]*13^i*19^j
były tego samego modulo16^20
zarówno dla początkowej tablicy o szerokości 600, jak i tablicy spakowanej, to jesteśmy skończeni.Aby trochę ułatwić, rozważymy tylko
600^2 = 360000
cyfry cyfrowe, tak że tablica o szerokości 600 ma po prostu kwadrat 600 x 600 cyfr. Ułatwia to wizualizację i jest ważny od tego czasu10^360000 ~ 2^(2^20.19) < 2^(2^30)
. Aby jeszcze bardziej uprościć sprawę, rozważymy tylko takie ciągi wejściowe, których kwadrat cyfrowy jest symetryczny wzdłuż głównej przekątnej, tak że pierwotna tablica i tablica spakowana są takie same. Pozwala nam to również zignorować początkowe odwrócenie łańcucha i numerację indeksów od prawej do lewej, które się wzajemnie znoszą.Na początek możemy przyjąć pierwszą liczbę
360000
. Aby uzyskać drugą liczbę, chcemy to zmienić, zmieniając niektóre cyfry, aby sumy były takie same modulo16^20
, zachowując symetrię kwadratu cyfry. Osiągamy to, znajdując listę trójek(i, j, k)
, abygdzie
1 <= k <= 8
jest kwota na zwiększenie cyfry 1 o (tj. przejście na cyfrę od 2 do 9 - moglibyśmy uwzględnić 0, ale nie potrzebowaliśmy jej) i0 <= i < j < 600
są parami indeksów.Raz mamy
(i, j, k)
trojaczki, zmieniamy cyfry na(i, j)
i(j, i)
aby1+k
uzyskać drugą liczbę. Trojaczki zostały znalezione przy użyciu chciwego algorytmu cofania, a dla drugiej liczby powyżej cyfry kwadrat wygląda następująco:Na przykład
(i, j, k) = (0, 1, 7)
odpowiada zmianie cyfr(0, 1)
(pozycji600*0 + 1 = 1
) i(1, 0)
(pozycji600*1 + 0 = 600
) na1 + 7 = 8
.Oto backtracker w Pythonie 3, chociaż dokładniejsza analiza wykazała, że mieliśmy szczęście, ponieważ tak naprawdę nie nastąpiło cofnięcie:
Jako bonus, oto niezbyt wydajny port skrótu w Pythonie 3. To było bezużyteczne.
źródło
PHP 4,1, 66 bajtów przez Ismaelowi Miguel
Znaleziono przy użyciu prostego iterowanego mieszania, zaczynając od 1:
źródło
hash(hash(hash(...(hash(1)...)))
.). Pierwszy łańcuch niemal natychmiast zszedł w pętlę. Nie musiałem nawet przywoływać mojego wielowątkowego urządzenia do krakowania skrótów.Python 3 (216) autorstwa Sp3000
Moje wiadomości są
Użyłem tego kodu Python 2 do ich wygenerowania:
Duży moduł był iloczynem dwóch liczb pierwszych
a
ib
. Wydaje mi się, że mieliśmy nadzieję, że uwzględnienie semiprime nie byłoby możliwe, ale wydaje mi się, że 128 bitów jest za małe, ponieważ jakaś strona internetowa od razu dała mi odpowiedź.Modulo grupy multiplikatywnej
ab
będzie miało kolejność (a - 1) (b - 1), co oznacza, że jeśli podniesiemy dowolną liczbę do tej potęgi, będzie to musiało dać 0 lub (zwykle) 1. Więc umieszczam 1 bit w miejscach, które skutkowały 2 (a-1) (b-1) są mnożone w hasz. Wtedy druga wiadomość jest w zasadzie 0, ale ustawiam jeden inny bit w każdej liczbie, aby długości były takie same.Myślę, że byłoby bardziej denerwujące, gdyby hash był wyrównany pod każdym względem, a nie tylko po użyciu wszystkich liczb pierwszych. Wtedy zbudowanie dla nich dowolnych wykładników nie byłoby tak proste.
źródło
C, 128 bajtów - autor: squeamish ossifrage
Następujące dwa ciągi znaków mają skrót do wszystkich zer:
Funkcja skrótu jest zbudowana w taki sposób, że bity wyższego rzędu nigdy nie wpływają na bity niższego rzędu, dlatego mogę wygenerować kolekcję ciągów, w których wszystkie
x
bity niższego rzędu są zerowe, a następnie mogę wypróbować połączone kombinacje tych ciągów, aby znaleźć gdzieś więcej niższe bity wynoszą zero itp. Jestem pewien, że istnieje więcej sposobów na przełamanie tego, a także sposoby, które wytwarzają znacznie krótsze łańcuchy, ale w ten sposób uniknąłem mnożenia matematyki.źródło
0x0000000a0000000a0000000a0000000a
mojego systemu, ale wciąż jest to całkiem niesamowite. (echo -ne '\x0a' |./hash
daje również ten sam wynik.)Python 3, 118 bajtów
i
(to znaczy: 9E400 i 9E4000)
Oba produkują
Kopiąc nieco głębiej, wydaje się, że jakakolwiek liczba całkowita, po której następuje k powtórzonych cyfr, tak że k> 128 i (k% 4 == 0) zwrócą ten sam skrót. Na przykład
H("1"+"1"*32*4)
iH("1"+"1"*33*4)
są oba13493430891393332689861502800964084413
. Hmmm, 128 ...źródło
Python 2, 161 bajtów, autor: Puzzled
i
Oba mają wyjście:
Liczby to 2 ^ 128 i 2 ^ 128 + (3 * 5 * 7 * 11 * 13 * 17) ^ 2 * 19 * 2 ^ 32.
źródło
Java, 299 bajtów autorstwa SuperJedi224
Pastebin dla
M
. W trybie binarnymM
ma 655351
s, a następnie 20
s.Pastebin dla
N
. W trybie binarnymN
ma 218451
s, a następnie 1747660
s.Oba zbiory
0
.Zauważ, że podstawą algorytmu jest
i.bitCount()*i.bitLength()+1
i ostatecznie bierzemy wynik do potęgii
i przyjmujemy mod 2 128 . Pomysł polegał więc na znalezieniu dwóch,i
które można podzielić przez cztery, ale gdzie pierwsze wyrażenie daje 2 32 . Można to łatwo zrobić , biorąc pod uwagę fakt, że 2 32 -1 i wybierając dwa czynniki dla liczby 1s i całkowitej szerokości bitu liczby.Edycja: Właściwie jest nieco więcej powodów, dla których
M
daje zero, ale możemy łatwo znaleźć więcej liczb, które dają zero z powodu mojego wyjaśnienia, używając innych czynników 2 32 -1, takich, że na końcu jest co najmniej 64 zer.źródło
C, 134 bajtów (autor Barteks2x)
i
oba hash do
ponieważ algorytm haszywa tylko ostatnią cyfrę!
źródło
C, 87 bajtów
Znaleziono za pomocą mojego bruteforcer kolizyjnego.
źródło
473E0B6ED5AF2B92 7EC2BC9B5E9F5645 -> 0000000000000000 0EAC34C8A9F94389
po 3525078917 wywołaniach funkcji skrótu ireal 14m24.970s user 48m42.410s
czasie.Python 2, 115 bajtów, przez piskliwy ossifrage
i
Wartość skrótu nie miała nic wspólnego z kolejnością bloków.
źródło
Python 2.x, 139 bajtów według Puzzled
H(2)
i
H(128)
oba wracają
16645614427504350476847004633262883518
.źródło
C ++, 239 bajtów autorstwa SpelingMistake
Za pomocą dostarczonego programu „głównego” następujące dwa dane wejściowe generują ten sam skrót:
i
Te pierwsze 8 bajtów wejściowych nie są przetwarzane , ze względu na ten błąd w kodzie:
bo
--i
FALSE gdyi==1
,q[0]
(pierwsze 8 bajtów:I
jestint64
). Zastąpienie warunku pętlifor(I i=n;i--;)
rozwiązałoby to.źródło
Ruby, 90 bajtów, autor: MegaTom
i
które są 2 i 11, po których następuje 40 bajtów zerowych. Więc oba mają 41 bajtów. Wartość skrótu jest dodawana na podstawie długości wejściowej każdego bajtu, a następnie jest odwracana dziesiętnie. Długość wejściowa kończąca się na
1
może zapewnić, że wartość skrótu zakończy się na0
dość szybko. Następnie odwrócenie powoduje zmniejszenie długości wartości skrótu o 1.Oba mają wartość skrótu
259
.źródło
C # - 393 bajtów - autor: Logan Dam
70776e65642062792031333337206861786f72
i70776e65642062792031333337206861786f7200
oba hash do18E1C8E645F1BBD1
.źródło