bmaj8PCosFLAJjeHaevvvchnJedmg2iujpePOPivI2x2asw0yKa2eA15xvFJMFe82RGIcdlvxyaAPRuDuJhFjbh78BFsnCufJkarwEyKa0azHxccw5qegpcP9yaO0FKoohanxgiAfK1Lqwba51bKtjacbvdjMmcBkiv8kd62sBd98c4twa98sgj3iPh7nkP4
rlaejTPrua1DhBdg0jrIoDBi8fc1GIJAigivIGaxs1OmfPcctNadK3HErvzPLCeDPD8fkMNPCBcIwuoGfEHegOfk9k9pwktslqaBenaati1uNthMiyk9ndpy7gdIz88iot6A09cbNeIMheyjBvbeegL7aGp7mCb91hCxnvgV5abfImrPfLbrbraAsN6loJgh
Kedua string hash to bb66000000000000d698000000000000
Sama seperti "C, 128 byte - oleh: squeamish ossifrage" bit orde tinggi tidak pernah mempengaruhi bit orde rendah, ini dapat dieksploitasi.
Kode
Visual C ++, menggunakan operasi string " tidak aman "
#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 byte oleh Sp3000
Perhatikan bahwa Martin retak terlebih dahulu, jadi saya tidak yakin apakah ini layak mendapat poin. Di sisi lain, saya memang membuat serangan preimage daripada tabrakan sederhana - hasil yang jauh lebih kuat. Ini berarti bahwa Anda dapat memberikan nilai hash sewenang-wenang, dan itu akan membangun input yang menghasilkan nilai hash itu.
Dan untuk menunjukkan bahwa itu berfungsi:
Dan untuk memberikan satu set angka tertentu yang bertabrakan:
sumber
Python, 109 byte oleh Sp3000
dan
keduanya menghasilkan
Algoritma membagi input menjadi potongan 128 bit, dan berulang kali memodifikasi hash (diunggulkan
42
) dengan masing-masing potongan, sebelum melakukan beberapa hashing tambahan di akhir. Untuk menemukan tabrakan, tujuan kami adalah menemukan dua angka yang menghasilkan hasil yang sama setelah menjalankan kode pseudo berikut pada setiap chunk:Karena hash diambil mod 2 128 kami ingin mencari angka yang menggeser semua hal menarik di luar kisaran bit ini. Tetapi hash diunggulkan
42
sehingga memiliki beberapa bit yang tidak terlalu signifikan untuk dimulai dengan:Ide saya adalah untuk menyingkirkan bit-bit itu ketika menambahkan potongan pertama. Jadi mari kita coba 2 128 -42:
Itu cukup sederhana jadi mari kita coba gunakan itu sebagai salah satu dari dua angka. (Memang, jumlah pertama tabrakan yang saya gunakan adalah 2 128 -42.
Sekarang bagaimana kita menemukan nomor lain dengan hasil yang sama? Baik setelah satu iterasi hash tidak
42
lagi, tetapi2**122
seperti yang baru saja kita tunjukkan. Sekarang dengan menambahkan potongan kedua ke nomor input kami, kami dapat menjalankan iterasi lain. Kita dapat memilih potongan kedua dengan argumen yang sama seperti argumen ini, yaitu kita ingin 2 128 -2 122 . Kemudian hasil antara setelahhash += chunk
akan sama dan kami berakhir dengan hasil yang sama di akhir.Jadi kita bisa menghitung dua angka tabrakan:
Kita dapat dengan mudah menghasilkan lebih banyak tabrakan seperti ini.
sumber
Mathematica, 89 byte oleh LegionMammal978
dan
Keduanya menghasilkan
0
.Prinsip dari polisi ini adalah untuk mengembangkan otomat seluler 1-D biner "acak" dari kondisi awal "acak" untuk sejumlah langkah "acak", dan kemudian menginterpretasikan 128 sel pertama hasil sebagai bilangan bulat.
Masalahnya adalah bahwa aturan ditentukan hanya dengan
Mod[#^2,256]
, sedemikian sehingga kelipatan 16 memberi aturan0
, yang merupakan aturan trivial di mana semua sel selalu nol. Jika input tidak habis dibagi 99 maka kita akan berevolusi setidaknya 1 langkah, sehingga output selalu nol. Jadi, dua kelipatan yang bukan kelipatan 99 pasti bertabrakan. Namun, input0
juga memberikan 0 (meskipun tidak pernah menggunakan aturan), karena kondisi awal hanyalah representasi biner dari input (yang semuanya nol dalam kasus ini).Selain itu, kita dapat menemukan tabrakan lain yang sepenuhnya independen dari aturan. Seperti disebutkan di atas, setiap kelipatan dari 99 berarti bahwa otomat seluler tidak berevolusi sama sekali, sehingga hasilnya hanyalah 128 bit pertama (paling signifikan) dari kondisi awal ... yang dengan sendirinya hanya nomor input. Jadi jika kita mengambil dua kelipatan yang tidak berbeda dalam 128 bit pertama (empuk ke kanan dengan nol), kita juga mendapatkan tabrakan. Contoh paling sederhana dari hal ini adalah
M = 99
,N = 99*2 = 198
.sumber
J, 39 byte
Angka pertama adalah:
Yaitu,
10000000
diulang 64 kali. Angka kedua adalah yang ditambah satu, yaituKeduanya menghasilkan
Penjelasan
Mari kita mulai dengan
x := H 10000000 = 146018215378200688979555343618839610915
, dany := 2^128
. Daripada menemukan yanga, b
seperti itua == b mod y
, kita akan mencari yanga, b
seperti itux^a == x^b mod y
, menggunakan menara listrik dalam algoritma.Tetapi harus ada
k
semacam itux^k == 1 mod y
, karenax, y
ada koprime, dan untuk ituk
harus kita milikia == b mod k
. Jadi kita dapat menemukan logaritma diskret dari 1 mody
, dan untuk langkah pertama kita dapatkanJadi sekarang kita ingin mencari dua angka
a, b
sedemikian rupaa == b mod k
. Untuk melakukan ini, kami menetapkany
untuk menjadik
dan mencoba menemukana, b
itux^a == x^b mod y
lagi. Menggunakan logika yang sama, kita mengambil logaritma diskrit lagi dan dapatkanKita ulangi ini sampai kita mencapai yang kecil
y
, pada titik yang sepele untuk menemukan dua angka yang hash ke modulo hal yang samay
. Setelah 63 iterasiy = 4
, pada titik mana pada dasarnya dua angka berfungsi.Berikut kode Mathematica untuk menghasilkan rantai log diskrit:
Ini memberikan output berikut .
sumber
2^(2^30)
batas, maka dari itu cek.Pyth, 8 byte oleh FryAmTheEggman
dan
Presisi titik apung tidak cukup besar untuk ini.
sumber
437409784163148
untuk keduanya. Saya ingin tahu mengapa ada perbedaan ...437409784163148
dan37409784163148
jadi saya kira itu baru saja kehilangan digit terakhir karena beberapa alasan, tetapi 99 ... 997 memberikan jawaban yang sama dengan 999 ... 98.CJam, 44 byte,
penggunajimmy23013Jumlahnya terlalu besar untuk dikirim, jadi di sini mereka berada di Pastebin: num 1 , num 2 .
Angka pertama adalah
600^2 = 360000
yang. Angka kedua sama, kecuali untuk perubahan berikut:Keduanya hash
271088937720654725553339294593617693056
.Penjelasan
Mari kita lihat pada bagian pertama dari kode:
Jadi jika kita dapat menemukan dua angka input sehingga jumlah
S[i][j]*13^i*19^j
modulo yang sama16^20
untuk array 600-lebar awal dan array zip, maka kita sudah selesai.Untuk mempermudah, kami hanya akan mempertimbangkan
600^2 = 360000
angka input -digit, sehingga array 600-lebar hanya 600 x 600 persegi digit. Ini membuat segalanya lebih mudah untuk divisualisasikan, dan valid sejak saat itu10^360000 ~ 2^(2^20.19) < 2^(2^30)
. Untuk menyederhanakan hal-hal lebih jauh, kami hanya akan mempertimbangkan string input seperti itu yang digit perseginya simetris di sepanjang diagonal utama, sehingga array asli dan array zip sama. Ini juga memungkinkan kita untuk mengabaikan pembalikan string awal dan penomoran indeks kanan-ke-kiri, yang membatalkan satu sama lain.Untuk memulai kita, kita bisa mengambil nomor pertama menjadi
360000
yang pertama. Untuk mendapatkan angka kedua, kami ingin memodifikasi ini dengan mengubah beberapa digit sehingga jumlahnya adalah modulo yang sama16^20
, sambil mempertahankan simetri digit persegi. Kami menyelesaikan ini dengan menemukan daftar tiga kali lipat(i, j, k)
sehinggadi mana
1 <= k <= 8
jumlah untuk meningkatkan digit 1 oleh (yaitu mengubah ke digit dari 2 menjadi 9 - kita bisa memasukkan 0 tetapi kita tidak membutuhkannya) dan0 <= i < j < 600
merupakan pasangan indeks.Setelah kita memiliki
(i, j, k)
kembar tiga, kita mengubah angka di(i, j)
dan(j, i)
untuk1+k
mendapatkan angka kedua. Si kembar tiga ditemukan menggunakan algoritma backtracking serakah, dan untuk angka kedua di atas digit persegi terlihat seperti:Misalnya,
(i, j, k) = (0, 1, 7)
terkait dengan mengubah digit(0, 1)
(posisi600*0 + 1 = 1
) dan(1, 0)
(posisi600*1 + 0 = 600
) menjadi1 + 7 = 8
.Inilah backtracker di Python 3, meskipun inspeksi lebih dekat mengungkapkan bahwa kami cukup beruntung, karena tidak ada backtracking yang sebenarnya terjadi:
Sebagai bonus, ini adalah port hash yang tidak terlalu efisien dalam Python 3. Itu tidak berguna.
sumber
PHP 4.1, 66 byte oleh Ismael Miguel
Ditemukan menggunakan hashing berulang sederhana, mulai dari 1:
sumber
hash(hash(hash(...(hash(1)...)))
). Rantai pertama menyatu menjadi lingkaran hampir seketika. Aku bahkan tidak perlu membuka cracker hash multithreaded saya.Python 3 (216) oleh Sp3000
Pesan saya adalah
Saya menggunakan kode Python 2 ini untuk menghasilkannya:
Modulus besar adalah produk dari dua bilangan prima
a
danb
. Saya kira harapannya adalah bahwa NP-tidak mungkin bagi kami untuk faktor semiprime, tapi saya kira 128 bit terlalu kecil karena beberapa halaman web memberi saya jawabannya segera.Modulo kelompok multiplikatif
ab
akan memiliki urutan (a - 1) (b - 1) yang berarti jika kita menaikkan angka berapa pun dari kekuatan itu maka harus menghasilkan 0 atau (biasanya) 1. Jadi saya meletakkan 1 bit di tempat yang menghasilkan 2 (a-1) (b-1) dikalikan ke dalam hash. Maka pesan lainnya pada dasarnya adalah 0, tetapi saya menetapkan satu bit lainnya di setiap nomor untuk membuat panjangnya sama.Saya pikir itu akan lebih mengganggu jika hash kuadrat pada setiap bit, daripada hanya setelah menggunakan semua bilangan prima. Maka itu tidak akan begitu mudah untuk membangun eksponen yang sewenang-wenang untuk mereka.
sumber
C, 128 byte - oleh: osifrque melengking
Dua string berikut ini sama-sama hash untuk semua nol:
Fungsi hash dibangun sehingga bit orde tinggi tidak pernah mempengaruhi bit orde rendah, oleh karena itu saya dapat menghasilkan kumpulan string di mana semua
x
bit orde rendah adalah nol, maka saya dapat mencoba kombinasi gabungan dari string ini untuk menemukan beberapa di mana lebih dari bit yang lebih rendah adalah nol dll. Saya cukup yakin bahwa ada lebih banyak cara untuk memecahkan ini, dan juga cara yang menghasilkan string lebih pendek secara signifikan, tetapi dengan cara ini saya menghindari melakukan banyak matematika.sumber
0x0000000a0000000a0000000a0000000a
di sistem saya, tapi itu masih cukup menakjubkan. (echo -ne '\x0a' |./hash
juga memberikan hasil yang sama.)Python 3, 118 byte
dan
(yaitu: 9E400 dan 9E4000)
Keduanya menghasilkan
Menggali lebih dalam, tampaknya bilangan bulat mana saja yang diikuti oleh k angka berulang sehingga k> 128 dan (k% 4 == 0) akan mengembalikan hash yang sama. Misalnya,
H("1"+"1"*32*4)
danH("1"+"1"*33*4)
keduanya13493430891393332689861502800964084413
. Hmmm, 128 ...sumber
Python 2, 161 byte, oleh Bingung
dan
Keduanya memiliki output:
Jumlahnya 2 ^ 128 dan 2 ^ 128 + (3 * 5 * 7 * 11 * 13 * 17) ^ 2 * 19 * 2 ^ 32.
sumber
Java, 299 bytes oleh SuperJedi224
Pastebin untuk
M
. Dalam biner,M
memiliki 655351
s, diikuti oleh 20
s.Pastebin untuk
N
. Dalam biner,N
memiliki 218451
s, diikuti oleh 1747660
s.Keduanya menghasilkan
0
.Perhatikan bahwa dasar dari algoritma ini adalah
i.bitCount()*i.bitLength()+1
dan pada akhirnya, kami mengambil hasilnya sesuai dengan kekuatani
dan membawanya pada mod 2 128 . Jadi idenya adalah hanya untuk menemukan duai
yang dapat dibagi oleh empat, tetapi di mana ungkapan pertama memberi 2 32 . Itu mudah dilakukan dengan memfaktorkan 2 32 -1 dan memilih dua faktor untuk penghitungan 1s dan total lebar bit dari angka tersebut.Sunting: Sebenarnya, ada sedikit lebih banyak alasan mengapa
M
menghasilkan nol, tetapi kita dapat dengan mudah menemukan lebih banyak angka yang menghasilkan nol karena penjelasan saya dengan menggunakan faktor-faktor lain dari 2 32 -1 sehingga setidaknya ada 64 nol pada akhirnya.sumber
C, 134 byte (oleh Barteks2x)
dan
keduanya hash
karena algoritma hanya hash digit terakhir!
sumber
C, 87 byte
Ditemukan menggunakan bruteforcer tabrakan saya.
sumber
473E0B6ED5AF2B92 7EC2BC9B5E9F5645 -> 0000000000000000 0EAC34C8A9F94389
setelah 3525078917 panggilan fungsi hash danreal 14m24.970s user 48m42.410s
waktu.Python 2, 115 byte, oleh ossifrage melengking
dan
Nilai hash tidak ada hubungannya dengan urutan blok.
sumber
Python 2.x, 139 bytes oleh Puzzled
H(2)
dan
H(128)
keduanya kembali
16645614427504350476847004633262883518
.sumber
C ++, 239 bytes oleh SpelingMistake
Menggunakan program "utama" yang disediakan, dua input berikut menghasilkan hash yang sama:
dan
The 8 byte pertama dari masukan tidak pernah diproses , karena bug ini dalam kode:
karena
--i
dievaluasi menjadi false wheni==1
,q[0]
(8 byte pertama:I
adalah anint64
). Mengganti kondisi loop denganfor(I i=n;i--;)
akan memperbaiki ini.sumber
Ruby, 90 Bytes, oleh MegaTom
dan
yaitu 2 dan 11 diikuti oleh 40 nol byte. Jadi mereka berdua memiliki 41 byte. Nilai hash ditambahkan oleh panjang input untuk setiap byte, dan kemudian dibalik dalam desimal. Panjang input yang diakhiri dengan
1
dapat memastikan nilai hash akan berakhir dengan0
cukup cepat. Kemudian membalikkannya mengurangi panjang nilai hash sebesar 1.Keduanya memiliki nilai hash
259
.sumber
C # - 393 byte - oleh: Logan Dam
70776e65642062792031333337206861786f72
dan70776e65642062792031333337206861786f7200
keduanya hash to18E1C8E645F1BBD1
.sumber