加密哈希高尔夫(强盗)


12

比赛结束了。

警察挑战中没有剩余的可靠答案。

加密哈希高尔夫的同伴线程

提醒一下,这是针对主要挑战的强盗规则:

任务

通过在强盗的线程中张贴以下内容来破解任何警察的提交:I中的两个消息MN,使得 H(M)= H(N)M≠N

计分

破解每个警察提交的内容可以使您获得1分。得分最高的强盗获胜。

如果是平局,则破解最长提交的并列强盗获胜。

附加规则

  • 每次提交的警察只能被破解一次。

  • 如果警察提交依赖于实现定义的行为或未定义的行为,则只需要找到在计算机上有效(可验证)的破解即可。

  • 每个破解都属于强盗线程中的一个单独答案。

  • 发布无效的破解尝试会禁止您破解特定的提交文件30分钟。

  • 您可能无法破解自己的提交。

Python 2.7,user8675309的22个字节

1

18

排行榜

  1. 电子商务:3个裂缝,393个字节
  2. MartinBüttner:3个裂缝,299字节
  3. jimmy23013:3个裂缝,161个字节
  4. Sp3000:3个裂缝,44个字节
  5. tucuxi:2个裂缝,239个字节
  6. 六。:2个裂缝,87字节
  7. feersum:1个裂纹,216个字节
  8. mathmandan:1个破解,139个字节
  9. 吱吱作响的ossifrage:1裂纹,134字节

Answers:


5

C,122字节-作者:Llama先生

bmaj8PCosFLAJjeHaevvvchnJedmg2iujpePOPivI2x2asw0yKa2eA15xvFJMFe82RGIcdlvxyaAPRuDuJhFjbh78BFsnCufJkarwEyKa0azHxccw5qegpcP9yaO0FKoohanxgiAfK1Lqwba51bKtjacbvdjMmcBkiv8kd62sBd98c4twa98sgj3iPh7nkP4
rlaejTPrua1DhBdg0jrIoDBi8fc1GIJAigivIGaxs1OmfPcctNadK3HErvzPLCeDPD8fkMNPCBcIwuoGfEHegOfk9k9pwktslqaBenaati1uNthMiyk9ndpy7gdIz88iot6A09cbNeIMheyjBvbeegL7aGp7mCb91hCxnvgV5abfImrPfLbrbraAsN6loJgh

两个字符串都哈希到 bb66000000000000d698000000000000

就像“ C,128字节-by:squeamish ossifrage”一样,高位永远不会影响低位。

Visual C ++,使用“ 不安全 ”字符串操作

#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;
}

太棒了!我实际上以一种奇怪的方式受宠若惊!:D
Llama先生2015年

另外,对于我自己的个人教育,当您说高阶位永远不会影响低级位时,您是什么意思?输入字符串或哈希状态的高阶位?
骆马先生2015年

@ Mr.Llama在哈希状态下,x和y的高位永远不会影响低位,因此,例如,如果在计算过程中翻转中间位,哈希的低位部分仍会正确显示。这使我开始忽略哈希状态最低位以外的所有内容,然后在完全控制哈希值的情况下,我继续进行下一层位,依此类推。
aaaaaaaaaaaa 2015年

凉!感谢您的解释!
骆马先生2015年

祝贺您赢得了强盗挑战!
丹尼斯

12

Python,109字节,Sp3000

请注意,马丁先破解了,所以我不确定这是否值得。另一方面,我确实进行了原像攻击,而不是简单的碰撞-结果要强得多。这意味着您可以给它一个任意的哈希值,它将构造一个生成该哈希值的输入。

M = 2**128

# The hash to crack.
def jenkins(n):
    h = 42
    while n:
        h += n & (M - 1)
        n >>= 128
        h *= 1025
        h ^= h >> 6
        h %= M

    h *= 9
    h ^= h >> 11
    h *= 32769

    return h % M

def egcd(a, b):
    if a == 0:
        return (b, 0, 1)
    else:
        g, y, x = egcd(b % a, a)
        return (g, x - (b // a) * y, y)

def modinv(a, m):
    g, x, y = egcd(a, m)
    if g != 1:
        raise Exception('modular inverse does not exist')
    else:
        return x % m

def invxorshift(h, s):
    r = h >> s
    while r:
        h ^= r
        r >>= s
    return h

def moddiv(a, b):
    return (a * modinv(b, M)) % M

def jenkins_crack(h):
    h = moddiv(h, 32769)
    h = invxorshift(h, 11)
    h = moddiv(h, 9)
    h = invxorshift(h, 6)
    h = moddiv(h, 1025)
    h -= 42
    return h

并证明它有效:

>>> from crack import *
>>> n = 2**128 + 1337
>>> h = jenkins(n)
>>> n2 = jenkins_crack(h)
>>> h2 = jenkins(n2)
>>> n != n2
True
>>> h == h2
True

并给出一组会碰撞的特定数字:

N: 2**128
M: 43617

3
我最初在沙盒中提出的建议是针对collison,原像和(长度稍为简化)长度扩展攻击得分,但我决定保持评分简单。当我编辑这些部分时,每个提交只能被破解一次的事实(这就是警察和强盗通常的工作方式)以某种方式丢失了。看到您的回答,我希望我一直保持原像攻击...
丹尼斯

9

Python,109字节,Sp3000

340282366920938463463374607431768211414

113982837842983129870077688367927159293402923522160868689804433865221255200726

既产量

132946164914354994014709093261515948032

该算法将输入拆分为128位的42块,并在最后进行一些额外的哈希处理之前,对每个块重复修改哈希(种子化为)。为了找到冲突,我们的目标是在每个块上运行以下伪代码后找到两个产生相同结果的数字:

hash += chunk
hash += (hash << 10)
hash ^= (hash >> 6)
hash %= 2**128

由于哈希是在mod 2 128中获取的,因此我们要查找将所有有趣的内容都移出该位范围的数字。但是散列被植入种子,42因此它开始时设置了一些不太重要的位:

000000000000000000000000 ... 000000000000000000101010

我的想法是在添加第一个块时摆脱这些位。因此,让我们尝试2 128 -42:

           000000000000000000000000 ... 000000000000000000101010     hash = 42
           111111111111111111111111 ... 111111111111111111010110     chunk = 2**128 - 42
          1000000000000000000000000 ... 000000000000000000000000     hash += chunk
10000000001000000000000000000000000 ... 000000000000000000000000     hash += hash << 10
10000010001000001000000000000000000 ... 000000000000000000000000     hash ^= hash >> 6
           000001000000000000000000 ... 000000000000000000000000     hash %= 2**128

这很简单,所以让我们尝试将其用作两个数字之一。(实际上,我使用的第一个碰撞数是2 128 -42。

现在我们如何找到另一个具有相同结果的数字?好了,经过一轮迭代之后,哈希值就不再存在42了,但是2**122正如我们刚刚展示的那样。现在,通过在输入数字中添加第二个块,我们可以运行另一个迭代。我们可以通过与此参数相同的参数来选择第二个块,即我们想要2 128 -2 122。这样,之后的中间结果hash += chunk将是相同的,最后我们将得到相同的结果。

因此我们可以计算碰撞的两个数字:

>>> 2**128-42
340282366920938463463374607431768211414L
>>> 2**128-42 + ((2**128-2**122)<<128)
113982837842983129870077688367927159293402923522160868689804433865221255200726L

这样我们可以轻松地产生更多的碰撞。


我也在破解它-差不多完成了。这是西方竞赛中最快的枪支吗?还是我还能获得积分呢?
orlp 2015年

@orlp通常只有第一名强盗才能得到分数。否则,一旦发布第一个裂缝,人们就可能会产生数百万条其他裂缝。
马丁·恩德

1
me脚= /想想那我就停止挑战了。我不喜欢和别人比赛-我只是想困惑。第一次裂开以后,每个人只有1次裂开,难道没有时间窗口吗?
orlp 2015年

@orlp沙箱中的原始版本具有三种不同的破解警察的方法,并且所有三种都可以独立发布。我想这是一个有趣的模型,需要进行研究。但是到目前为止,在以前的CnR中,允许多个裂纹将比解决挑战更具挑战性。
马丁·恩德

1
看到我对原像攻击而不是碰撞的回答:)
orlp

8

Mathematica,Legion发行的89个字节

0

16

两者都屈服0

此警察的原理是从“随机”初始条件演化“随机”二进制一维细胞自动机,进行“随机”步数,然后将结果的前128个单元格解释为整数。

问题是该规则仅由决定Mod[#^2,256],因此16的任何倍数都会产生rule 0,这是一个琐碎的规则,其中所有像元始终为零。如果输入不能被99整除,那么我们将至少演进1步,因此输出始终为零。因此,不是99的倍数的任何两个倍数肯定会发生冲突。但是,输入0 将给出0(尽管从不使用该规则),因为初始条件只是输入的二进制表示形式(在这种情况下为全零)。

顺便说一句,我们可以找到完全独立于规则的其他碰撞。如上所述,99的任何倍数意味着根本不会演化细胞自动机,因此结果只是初始条件的前(最高有效)128位……它本身只是输入数。因此,如果我们采用前128位不变的两个倍数(在右边用零填充),我们也会遇到冲突。这个最简单的例子是M = 99N = 99*2 = 198


8

J,39个字节

第一个数字是:

10000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000

10000000重复64次。第二个数字是加一,即

10000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000001

既产量

322124197561777885386414076216564234267

说明

让我们从x := H 10000000 = 146018215378200688979555343618839610915和开始y := 2^128。而不是寻找a, b这样a == b mod y,我们会寻找a, b这样x^a == x^b mod y,利用该算法的电力铁塔的。

但是必须有k这样的东西x^k == 1 mod y,因为x, y是互质的,为此k我们必须有a == b mod k。因此我们可以找到1 mod 的离散对数y,对于第一步,我们得到

x ^ (k = 85070591730234615865843651857942052864) == 1 mod 2^128

所以现在我们要找到两个a, b这样的数字a == b mod k。为此,我们将其设置y为,然后再次k尝试查找。使用相同的逻辑,我们再次采用离散对数并得到a, bx^a == x^b mod y

x ^ (k = 21267647932558653966460912964485513216) == 1 mod 85070591730234615865843651857942052864

我们重复进行直到得到一个小数y,此时找到两个以模形式哈希到同一事物上的数字是微不足道的y。经过63次迭代y = 4,基本上任何两个数字都可以工作。

这是生成离散日志链的Mathematica代码:

k = 0; x = 146018215378200688979555343618839610915; y = 2^128; While[y > 10, y = MultiplicativeOrder[x, y]; k++; Print[k, " ", y]];

这给出以下输出


稍短一点的版本是,如果前几百位数字相同,则其余的输入根本不重要。实际上,通过数学打破这一点是过分的。
aaaaaaaaaaaa 2015年

@eBusiness是的。原来,在这里没什么大不了的,但是最初我担心超出2^(2^30)限制,因此担心。
Sp3000 2015年

实际上,我怀疑在第512位数字以外的任何事情都很重要的情况下,可能无法构造字符串。您设法产生了最坏的情况。最简单的破解必须是利用内部的前导零:“ 100000001”“ 1000000001”。
aaaaaaaaaaaaa 2015年

7

Pyth,8个字节,由FryAmTheEggman提供

99999999999999999999999999

99999999999999999999999998

浮点精度还不够。


我实际上为此获得了不同的结果,但我确实相信该策略仍然有效,因此我将其标记为“破解”。快速工作:P
FryAmTheEggman,2015年

嗯,很奇怪。我都437409784163148为。我不知道为什么会有区别...
Sp3000

您可能正在使用python 3.5对吗?我尚未更新,仍在3.4上,仅此而已?
FryAmTheEggman

@FryAmTheEggman我正在使用在线解释器,实际上是…
Sp3000 2015年

实际上,是的43740978416314837409784163148所以我猜它由于某种原因而丢失了最后一位数字,但是99 ... 997给出的答案与999 ... 98相同。
FryAmTheEggman 2015年

6

CJam,44个字节,用户 jimmy23013

这些数字太大而无法发布,因此这里是在Pastebin上:num 1num 2

第一个数字是600^2 = 3600001。第二个数字是相同的,除了以下更改:

Positions to change to "2": 605, 1811, 3001, 6603
Positions to change to "4": 1805, 3003, 57348, 208895
Positions to change to "5": 602, 1201, 2405, 3004
Positions to change to "6": 1203, 1802
Positions to change to "7": 12, 609, 5401, 7200
Positions to change to "8": 1, 2, 4, 6, 600, 1200, 1808, 2400, 3600, 4803

两者都散列为271088937720654725553339294593617693056

说明

让我们看一下代码的前半部分:

lW%                e#  Read input number as string, and reverse
600/               e#  Split every 600 digits, forming a 2D array
_z                 e#  Duplicate and zip, swapping rows and columns
{           }%     e#  For both arrays...
 JfbDb             e#  Find sum of S[i][j]*13^i*19^j, where S are the character values
                   e#  and the indices are from right to left, starting at 0.
      GK#          e#  Take modulo 16^20

         ...  ...  e#  (Rest of code irrelevant)

因此,如果我们可以找到两个输入数字,以使初始的600宽数组和压缩数组的总和S[i][j]*13^i*19^j具有相同的模16^20,那么就可以了。

为了使操作更简单,我们将仅考虑- 600^2 = 360000位输入数字,因此600宽的数组仅是600 x 600平方的数字。这使事情更容易可视化,并且从开始就有效10^360000 ~ 2^(2^20.19) < 2^(2^30)。为了进一步简化,我们将仅考虑数字平方沿主对角线对称的输入字符串,以使原始数组和压缩数组相同。这也使我们可以忽略初始的字符串反转和从右到左的索引编号,它们相互抵消。

首先,我们可以将第一个数字设为3600001。要获得第二个数字,我们想通过更改一些数字来修改此数字,以使总和具有相同的模数16^20,同时保持数字平方的对称性。我们通过找到三元组列表来完成此操作,(i, j, k)以便

sum of k*(13^i 19^j + 19^i 13^j) == 0 mod 16^20

其中1 <= k <= 8将数字1增加的数量(即,将数字从2更改为9 –我们可以包括0,但我们不需要),并且0 <= i < j < 600是索引对。

一旦我们有了(i, j, k)三胞胎,我们改变了数字的(i, j)(j, i)1+k获得第二个数字。使用贪婪的回溯算法找到了三元组,数字正方形上方的第二个数字如下所示:

188181811111711 ...
815112111711111 ...
851611111111111 ...
116114118112111 ...
811115111111111 ...
121451111111111 ...
811111111111111 ...
111111111111111 ...
111811111111111 ...
171111111111111 ...
111111111111111 ...
111211111111111 ...
711111111111111 ...
111111111111111 ...
111111111111111 ...

............... .
...............  .
...............   .

例如,(i, j, k) = (0, 1, 7)对应于将数字(0, 1)(position 600*0 + 1 = 1)和(1, 0)(position 600*1 + 0 = 600)更改为1 + 7 = 8


这是Python 3中的回溯器,尽管仔细检查发现我们很幸运,因为实际上没有发生回溯:

n = 16**20
L = [(k *(pow(13,i,n)*pow(19,j,n) + pow(19,i,n)*pow(13,j,n)) % n, i, j, k)
     for i in range(600) for j in range(600) for k in range(1, 9) if i < j]

L.sort(reverse=True)
stack = [(n, 0, [])]

while stack:
    k, index, result = stack.pop()

    if k == 0:
        print(result)
        break

    if index == len(L):
        continue

    stack.append((k, index+1, result)) # Don't include triplet

    if L[index][0] <= k:
        stack.append((k - L[index][0], index+1, result + [L[index][1:]])) # Include

对于奖金,这里是在Python 3这是无用的散列的不那么高效的口岸。


5

PHP 4.1,66字节伊斯梅尔米格尔

$ A=0111129112911291111111111111111111111111 php hash.php 2> /dev/null ; echo
0100038003800381129111111111111111111111
$ A=0111129112911291129111111111111111111111 php hash.php 2> /dev/null ; echo
0100038003800381129111111111111111111111
$ cat hash.php 
<? $a = getenv("A"); for($l=strlen($b.=$a*1);$i<40;$o.=+$b[+$i]^"$a"/$a,$i++);echo$o;

使用简单的迭代哈希发现,从1开始:

$ i=1; while true; do i=$(A=$i php hash.php  2> /dev/null); echo $i; done | head -n 10
0111111111111111111111111111111111111111
0100000000000001129111111111111111111111
0111129111111111111111111111111111111111
0100038000000001129111111111111111111111
0111129112911111111111111111111111111111
0100038003800001129111111111111111111111
0111129112911291111111111111111111111111
0100038003800381129111111111111111111111
0111129112911291129111111111111111111111
0100038003800381129111111111111111111111

是的,那个被破解了。到达那里花了多长时间?
Ismael Miguel

第二次尝试。第一次尝试查看前100个哈希值,第二次尝试创建哈希链(即hash(hash(hash(...(hash(1)...))))。第一链几乎立即收敛为一个循环。我什至不需要启动我的多线程哈希饼干。
六。

翻译:很弱的哈希?
Ismael Miguel

Yes.󠀠󠀠󠀠󠀠󠀠󠀠
六。

5

Sp3000的Python 3(216)

我的留言是

5012053369354645637214643587103597313576086380250249302980438772005248488380915054746146050001036696049972235875591571028140916001206596142280971107479334216535925703480968283657357930602076844092875640359192729378384507238123245417656548512647301639542279794868512420586823155070914644206130805893968511673770843170450832829657206145931885656157628306896903719624729809643572222159364893644113710867223921580178741177106141068298067479650611992859787419779579962211254029169589775046869542029842374359998053713002047081002506346875804341770199884355810931652447801492691887376948615365487982834690942054717077615539311699691010938426302886867891090301248321702485904291177813145565144089044261424329155436660979948932491709511914065619715728353376578192548334780893602675684085757434059540582004872746967999949306946618036846307799677491651967418565531672392468089533111553281620101129322575737949904022139471688252420467041529301533363008476437812216585923822571793353317799365005036029476865
5012053369354645637214643587103103086948976188724715498910865650846170784131001427390927276355140411160919276493388206817700368694224128444524223814513348177926532982330730066315320819293979046126543806115318009892783577432467861426768883700930779409885418980853424256180864755881414774514084197887594253752179391098292488771920695965135791582218083012144604515253506370334133858904659263953147111654656123599460222236152128559750436960308887683690915261431659087040402402092795259541564130228515353133867041828417398395559815392177084002004583988047406317670433664624642858480970640416500369367395538257341309676777745698712896295462462064271676447460293684100001583256400774270688958051470568447233589146620275159126426142305307007744396679875427883384557759778766330566230012377845843842097372663092379922300568052486301863154557664156185573021849420011058607321977550938866119133331529852821217331665195832442542012455132139770813510559894254061471149750738447764616026512400623344132554752

我使用以下Python 2代码生成了它们:

a,b = 14460445391122031029,16815296360833931837 #http://www.numberempire.com/numberfactorizer.php
pr = ~-a * ~-b

m0 = reduce(long.__or__, [long(b) << 26*i for i,b in enumerate(bin(pr)[2:])])
m1 = 1 << 26*i-1
m0 |= m1

#print m0, m1
print f(m0), f(m1)

大模量是两个素数a和的乘积b。我猜希望是我们把半素数分解为NP是不可能的,但是我想128位太小了,因为某些网页马上给了我答案。

乘法群模的ab阶数为(a-1)(b-1),这意味着如果我们将任意个数提高至该幂,则它必须得到0或(通常)为1。所以我将1位放在导致2 (a-1)(b-1)被乘以散列。然后另一个消息基本上是0,但是我在每个数字中都设置了另一个位以使长度相同。

我认为,如果每个位上的哈希都平方,而不是仅在使用所有素数之后才是更令人讨厌的。那么为它们建立任意指数并不是那么简单。


很好的工作:)是的,我想到的漏洞基本上是半素在代码中可见,并且我意识到Mathematica可以立即将其分解。
Sp3000

+1您的代码很难阅读,但否则会产生很好的指导意义。
aaaaaaaaaaaa 2015年

5

C,128字节-作者:squeamish ossifrage

以下两个字符串都哈希为全零:

dddl|lddH4|@dhxdxXdh0TXPdhhdx(dTxtlpdd@4Lhd|hdDpdhDdXLdXP4(PdddL|ldXdD(lddX4|0hddp4|ddP4Lxdp0dP@dhpTxPdhXdXxdhHDxHdllLttdhPT8pd(pT8Pdd0TL8dlLLTtddPtl8dP@DPPdhhDxhd804(pdh0Txpd@DDpLdhL4xtdXXdHXdd04lXht40dlddh4|@ddPTLXdhhDXHhtPH40dh0t8pd(pt80dhPtX0dhLtXtdhLT8thlLplTdhpt80dh0txpdhHDX(hdX8txdhhdxHdp|d@tdhlTx4dlptdxdh0T8PdT@t|Hdd@tL(ht(8DhdhHD8(hpHHP8dhLtXtdX8dhxdhpt8Pd@(D@Hdd@tLhdtxTLPdd0tlxhhL8X|dd8t|0dT04|Xddxt|phxxxhhdhpt8PhhxX8hdhlTX4dd4l||dd@TLHdXlTHtdhHd8hdX0THPdh(D8(d8xdh8dhp4xPd0HDp(dhl4xTdxlthtdhlTx4d8lT(TdhhdXHdphdP(dhp4x0d0Xd0XddTl||d88DH8dhhdxhdx|tHDdhLT8Thll0lTddPTlXdxXd(xdd0Tlxdhp480dhp4x0dd|LltdhPt80dtll|dddPTlXdxXd(xdd0Tlxdhp480dhp4x0dd|LltdhPt80dtll|dddP4Lxd|ptT8dhddxldH|4xDdhp4x0dDdl|LdhtD8|hhHx88ddpTL8hhphx@dhtd8|dphDP(dh0tx0hhDHx4dhpt8Pd@(D@HddLLLDhh|xxldhl4xTdhL4x4dhPt8Pd(HDx(dh(D8Hd4PT|8ddH4|@hh4H8ddhxd8XdDP4lxdhHd8hdl04d8ddXT|phdh8Thdd@TlHdhXdxxdllL44dD@4lHdhxdxXhd8XtxddLlLddT@T|(dhxdXXd|P44Xdhpt8pdlHDT0dhL4Xtd@ldpDdddl|LdXP4h0dhltXtdX8d(Xdh|tXdhhLXX|dhxd8XdP@D0PdhXDxXhtpHtPdd84|pddtl||dh(dx(d88Dh8ddx4|PhtT0DLdd@tL(hdX8Txdhp480d08d08dlll44d4dLLldhTdX|hh8Xxhdh048pd08d08ddPtL8d4H4l@dhhdxHd|pt4Xddp4lXhp(hPxdh|48DdxhDh(ddLlldd8XdH8dddl|LdLHDT0dhpt8pdlHDT0dh(d8hdTHtl@ddptl8dt84LPdh8dxxdlptD8dd04lxhhH8XxddDl|ldP|D@4ddTl||d|ptT8dh(dXhhd8X48dhPtXpd(8DxXdh@TX@dDP4L8dhpTX0d4@4|hdhHdxHdX8DHxdhPT8PhllplTdh0TXPhlXHLXddp4lXhtHXD(dhP4X0htH8dhdhLTx4hpxHPHdhhd8(dX8DHxdhpt80hhdHxTdlll44d@Hd@(dhhDxhdh0t8Pddh4|@ddh4|@dhptx0dpPD0@ddPtlxdhPT8pdhhdX(htTpDLdd@4L(dLHDtpdhxd8xdt84lPdlpTdxdDPTLXddLLLDdxlThtdlhd4PdXLTh4ddptLxd|@44(dhhd8HdtDLLlddxt|pd|hDd0ddPtLXhl@H|pdhDD8ld8dDhLdhXDXxdDxT|PdhHD8hdp8dpxdhp480d@XD@xddpTLXdHhD8(ddllLDdD|LL4dhpt80d@LdPDdh|4xDdP8dpXddLllddl8d4@dhptXpdd(4|@dhltx4d0Dd@LdhptxphdPHdpdhl4xTdxlthtdhHD8HdTdllldhLtX4dXP4(PdhLTxTd4X4LpddlllDdlpTD8dllltTdL(dtPdhDDxLdhLTx4dhptx0d|0T4Xdhl4xTdHL4XtdhpTXpdLp4dxddHt|@dHL484dhHDXHdHLtxtdhDdXldxL4H4dh|TxDhh8xX(dhLt8td8Lt(TdhHDx(d4DlLlddXT|PdHHD8(dlll44dlP4dxdd@tL(dL@4dhdd0tLxd4X4l0dhhdxhdDlLldddLLlddD04l8ddPtlxd(hd8hdd(T|@hdDp4|ddP4Lxdp0dP@dhptXpd(p4X0dhhd8(d8pT(0dh8d8Xhd(XT(dhddxLd@XD@8dd@tlhd@ld0ddhTD8|hhPH8@ddtl||dH0Tx0ddLlLddhp480dhHdxhd4lL|DdhXD8xdhhDX(dh048pd4Ll|ddddl|LdXP4h0dlll4thhdhxtddP4LXdhXdxXdhpTX0hdXXtxddlLLddx0Th0ddTl||hlhhlHdd|Ll4dHDdXldhhDX(hpxh0HdhDDXLdXDDhLdlhDTpht8Xdxdhpt8phhHXX8dd(t|@dHl4xtddp4LXhxhXH8dhDDxldDXt|PdhTDX|d|0ttxdhdDXLdDLLLddd84|PdT84LpdlhDTphl8hlxdhXD8xdHpt8Pdlhd40ddHT|@dhxdX8dhlT84dh|T8dhlXHLxdhxDxXdT4lL|dlllttd@xd@xdhhDXHhtXXD8dh(d8(d4p4|8dd04lxdxPThpdhHD8Hhdhx4hdhl4xthl|pLDdhltX4dhP4XPdd0Tlxdl@tDhddP4lXd0xD0xdhHD8Hd@8D@xdh0T8Pd0XDpxddPtl8dP@DPPdhhDxhd804(pdd04L8hpxHphdhDdxLdppD0@dd@tl(d88dHXdh0txpdXhDhHdd@Tlhdx8DHXdh0tXPdxxdH8dhPT8Pd484LPdlhD4pdxxdHxdd|Lltdhptx0dhlTx4hp8HPhdhPt8pdt4lL|ddtl||dH0Tx0dhxd8xhl@H|pddLllDhldP||dhdD8ldXLTHTdlhDTpddllLddd04lxhhH8Xxdh|48DdP8d0XddLLldd|@44hdhhd8hd4x4L0dhltXthh4H8Ddh4DX|dD@Tlhdh0tXpd8|T(ddhtDX|dlhdTPdd@tLhdThTl@dh8D8xdT(TL@dd@Tl(d8Hd(hdhXdxxhtHXdhdd0tl8d|HDDPdd8T|PdH04xPdd@Tl(d|@4t(dd(4|@dHp4xpdhpt80dh0txpdhp48phdXxTxdhhDXHhtPH40dh0t8pd(pt80dd8T|pdlxdt@dhp48PdD0TLXdh0t8Pd|lldTdh|t8DhphHp8

ddTl||d4|L|4dhptX0d4dllLddxT|pdxXdH8dlhDtPhlpH|@dd|Lltdhptx0dhlTx4hp8HPhdhPt8pdt4lL|ddtl||dH0Tx0ddLLLDd8tdH|dhDD8LdtxtLpdhxD8Xhd8xtxdhPt8Pd(8DX8dhddxLd0xd08dd0Tlxdxdd(Lddh4|@dXpt(Pdh048pd0xd0xdhhDX(d8p4Hpdh0480d(8DX8dhL4x4d4PT|XddPTLXdPDd@Ldddl|ld(P4X0ddDL|lht88DXdhPtxpd((Dx(dh0tx0dxXd(8dhpT8Pd0xD0XdlhD4pdT0T|8dh04XPht0H40dlhDtpdpHDP(dhlTXtdPHdpHdhXDxXhpPH0pddDl|lhltp|Ldh04x0dtXTL0ddLLLDdLhdtpdhL4xtdHDdXLddxt|0d4X4l0dh(Dxhdx04h0ddllLDd0PD0@dhXDxxhdx848dhDDxldpXDpXdhPt8pdhltxTdd04lxhhH8Xxdh|48DdP8d0XddLLldd|@44hdhhd8hd4x4L0dhltXthh4H8Ddh4DX|dD@Tlhdh0tXpd8|T(ddhtDX|dlhdTPdhlTXtdTX4L0dd@Tlhhh8xXHdhPt80d|XdD@dhp4xphd4Ptldd|LL4dL|ltDdhPTx0d80T(pdhpt8pd|pTtXdhpTX0hhth8Ddhxd8xdphdP(dh8D88dp(DPhdhHD8(htxXdXdh8dXXdXpTH0ddx4|PdpXDPxdhXDXXdxxdhXdhlt8Td@xD@8dhP4XPdhltX4dd@tlHdhXDxxdhPtXPd(8Dxxdh0t8PhdpHd0dh(D8HdX(D(Hdd@tLhht|@4Tdd@4lHdttll|dd0tlXhh|xxldd@TLHdlHdTPdd|LL4dt@T|hddx4|PdlHdtPddTl||d88DH8dlhdTpd40t|xddht|@dpPDP@dhHDxHhxthHDdhddxldxtDH|dhltx4d8Dd(ldd|LLthp0H0Pdhl4x4d|0T4Xdd|ll4dt8tLPdd@4lhd|0TTXddPtLXd(8d8xdhPTxPdHxd8xdhHDX(ddLllddhp48Pd0@d0PdhptxpdX(DhHdd0TlXhtPHTPddh4|@dTDlLldhDDxLhp(hPxdhdD8ldXLTHTddPtLXdTh4L@dhLtxTdlpTd8dhPtXpdhLtX4ddPTlXdxxdhXdhhd8(d404|8dhTd8|dhL4Xtddp4l8d4X4LpdhL4Xtd@ldpDdddl|LdXP4h0dhpTX0htXxDxdhpt8pddLlLddhp4XPhp0H00dh4Dx|dlp4D8dhPtxpd((Dx(dh0tx0dxXd(8dhDDxlhlL0ltdhhDxHd@|d0TdhHdxhdL0tD8dhhD8hhl|pLdddxt|pd|hDd0ddPtLXhl@H|pdhxDXxd8DdhldlhdtphpphppdhpT8PdH8dxXdlhd40dtXtlPdhTd8|dXlthtdhTDX|dx|4HDddxT|pdHDd8ldhL4X4dhP4XpdhtDx|ddXt|Pdh|T8DdHhdxhddLLLDhlxHl8dh0tXPd|(ddPddDL|LdHhdxhdhp4x0dl8dT@ddXT|phdh8Thdh(DXhd0HDP(dddl|lhd(xT(dhXdXxdTxtl0dd|lLtd8|4hddd4l||dXLTh4dd04lxdP8DP8ddxT|0dXXdh8ddP4lxd0@DpPdh8dXxddp4lxdhLt8tdHTdx|dh4Dx|dxLTHtdhhd8hd@DDpldd04LXdXlT(tdhXdXxdhPT8pdh(DXHdP@dp0ddP4LXdXpThPdllL4td((D8(dh0tXpd|(ddpdh(DxhhdL@DDdhHDx(dxL4(tdhLtXtdl@4dHdhxd8xdTh4L@dhXDXXhhdH8Tdd8T|PdH04xPdlllT4hllpLtdhhDXHhxxXhhdhXDxXdPDd@Ldd0TlXdHLtX4ddDL|ldXLT(4dhPtXPdXXd(8dhpt8phdH8thddxT|pd(ptXpddP4LxdLXDT@dhpT80dLptDxddxt|pdP@Dp0dhptx0d|0T4XdlpTdxdxpt(PdhHD8(d4TlL|dhHDx(d@hD@(dd@tl(d88dHXdh(Dx(d4pT|xddPtl8dP@DPPdhhDxhd804(pdhHD8Hhdhx4hddP4lxhdhXt(dhxdX8dp@DppdlllT4dP0dp@dddl|ldH8DXXdllLT4dPXdp8dd@tLHdlPTd8ddtL||d8PtHpddHt|@hd|@d4dh(dX(hdhXT(dhpT80hdHX4(dlpTdxdtDlLlddxT|pd(ptXpddP4LxdLXDT@dhpT80dLptDxddxt|pdP@Dp0dhptx0d|0T4XdlpTdxdxpt(PdhHD8(d4TlL|dhHDx(d@hD@(dddL|lhtph40dhpTxPdlp4dXdhDDxldpxD08dh(dX(dHlTxTdd|ll4d40t|Xdh0480ht@hT@dhptXphdHxT(dh(D8Hd4PT|8dhpt8pd88dhXddDl|LhxdHHtddPtlXd|pt4Xdd0Tl8d0(D0hdhhd8hdppd0@ddPTlXd8P4hpdhlTx4d8dDhLdd@TLhhllplTddXT|0dH|4XDdh|4xDht8XD8ddptl8dH8d88dd|LLTdh(DXhddHt|@hpXhp(dhdDxLdDhT|@dhP4X0dXhDHhdh0T8Pd((dxhdhhDx(hdx8Txddp4LXd8xDH8dhPTXpdlPtD8dh(DxHd@8D@Xdhl48Td00Dp@dhLT8Tdp(d0(dhhd8(d404|8dhhdx(dx0T(pdd|lL4ddXt|Pdd0TlXhxdH(4ddllLDhhLXX|dhXDx8hl8hLxdhpT80dLPtDXdhptX0dPXd0XddP4lxd0@DpPdlptd8dl(dTPdhxDx8d(ptX0dhpT80htxxdXdhhDxhdXltHtddh4|@d@|dPTdhdDXLhpph0Pdhp48Pdt4lL|dh04xpdLpTD8dd@4lhdl8dt@ddhT|@dPxDp8dd04lXd40t|xdd0TLxdTdlLLddpTLXd|pTT8dd04lxhhH8XxdhddxlhddPT|dd04LXdlhd4pdh8d8xhh|8XLdhxd8xd(8d8xdhp48pd(8DX8dhhDXHd4dllLddx4|0d8PTH0ddPtlxd|P44XdlpTdxd(XDXXddpTlxdHltX4dhLTxtd|HDD0

建立哈希函数是为了使高阶位永远不会影响低阶位,因此我可以生成一个字符串集合,其中所有x低阶位均为零,然后我可以尝试将这些字符串的级联组合找到更多的低位为零,等等。我很确定有更多的方法可以解决这个问题,也可以产生更短的字符串,但是这样我避免了很多数学运算。


太棒了!它们都哈希到0x0000000a0000000a0000000a0000000a我的系统上,但这仍然非常惊人。(echo -ne '\x0a' |./hash也给出相同的结果。)
r3mainer

1
@squeamishossifrage每个字符串之后都有一个胭脂红换行符,没有的话它是纯零。
aaaaaaaaaaaaa 2015年

哦,是的,我的错:-)
r3mainer

4

Python 3,118个字节

int(H("9"+"0"*400))

int(H("9"+"0"*4000))

(即:9E400和9E4000)

两者都产生

83909358607540647658718900164058931893

深入挖掘,似乎任何整数后跟k个重复数字,使得k> 128和(k%4 == 0)将返回相同的哈希值。例如,H("1"+"1"*32*4)H("1"+"1"*33*4)都是13493430891393332689861502800964084413。嗯128 ...


4

Python 2,161个字节,由不解之谜

340282366920938463463374607431768211456 (decimal)
100000000000000000000000000000000 (hexadecimal)

340282366920938468780317283222139437056 (decimal)
100000000000001203B66F94300000000 (hexadecimal)

两者都有输出:

83F172CC3D050D131F64FD04B8181DC2

数字为2 ^ 128和2 ^ 128 +(3 * 5 * 7 * 11 * 13 * 17)^ 2 * 19 * 2 ^ 32。


3

Java,SuperJedi224编写的299字节

Pastebin M以二进制形式,M具有65535 1s,然后是2 0s。

Pastebin N以二进制形式,N有21845 1s,然后是174766 0s。

两者都屈服0

请注意,算法的基础是i.bitCount()*i.bitLength()+1,最终,我们将结果i取为2 的幂并将其取为mod 2 128。所以这个想法只是找到两个i可以被4整除的东西,但是第一个表达式为2 32。通过分解2 32 -1并为1s的计数和数字的总位宽选择两个因子,可以轻松完成此操作。

编辑:实际上,为什么M产生零的原因还有很多,但是由于我的解释,我使用2 32 -1的其他因数,使得最后至少有64个零,因此我们可以轻易地找到产生零的更多数字。



3

C,87字节

$ echo B075343F9832CD60 | ./hash6_ ; echo
fc2e9f02bd284bd1
$ echo 5914BD1B71164C77 | ./hash6_ ; echo
fc2e9f02bd284bd1

使用我的碰撞蛮力发现。


也许是因为只有64位。
六。

做得好:-)花了多长时间?
r3mainer

运行该程序大约7分钟。现在重新开始测量。
六。

1
发现了另一个冲突:473E0B6ED5AF2B92 7EC2BC9B5E9F5645 -> 0000000000000000 0EAC34C8A9F943893525078917哈希函数调用和real 14m24.970s user 48m42.410s时间之后。
六。

3

Python 2,115字节,通过ossifrage进行压缩

1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222

2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222211111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111

哈希值与块的顺序无关。



2

C ++,SpelingMistake 239字节

使用提供的“主”程序,以下两个输入产生相同的哈希值:

echo -n "dog" | ./h
481c27f26cba06cf

echo -n "fog" | ./h
481c27f26cba06cf

由于代码中存在以下错误,因此从未处理输入前8个字节

 for(I i=n;--i;) // and then we use q[i] for this iteration

因为--i当时(前8个字节:是)i==1,结果为false 。用替换循环条件将解决此问题。q[0]Iint64for(I i=n;i--;)


看起来输入的前8个字节只是被忽略了。
六。

似乎是代码中的错误;该修复程序将后缀而不是前缀。
tucuxi

1
也有非Bug冲突(请参阅原始问题的注释)。
六。

2

Ruby,90字节,作者:MegaTom

4271974071841820164790043412339104229205409044713305539894083215644439451561281100045924173873152

23495857395130010906345238767865073260629749745923180469417457686044416983587046050252582956302336

分别是2和11,后跟40个零字节。因此它们都有41个字节。哈希值与每个字节的输入长度相加,然后以十进制反转。以。结尾的输入长度1可以确保哈希值0很快结束。然后将其反转可将哈希值的长度减少1。

两者都具有哈希值259


2

C#-393字节-作者:Logan Dam

70776e65642062792031333337206861786f72并且70776e65642062792031333337206861786f7200都哈希到18E1C8E645F1BBD1


凉!您能解释一下如何破解吗?也许是“错误的填充”?
拉丹2015年

@LoganDam这是所有在输入周围切换的代码,最终处理8个字符的倍数,如果输入长度不是8的倍数,则用零代替。如果我在正确的位置添加一些零,它们只是代替了填充,而填充是第一位。
aaaaaaaaaaaa 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.