C++ 任何种子的同一字符串上的CRC32哈希冲突

C++ 任何种子的同一字符串上的CRC32哈希冲突,c++,hash,sse,crc,crc32,C++,Hash,Sse,Crc,Crc32,我试图找到seed来散列最大可能长度的小写字母的短字符串,而不会发生冲突。 我选择了SSE 4.2 CRC32来简化任务。对于长度为4、5、6的种子,在某个合理的小值(我不能无限等待)内没有碰撞 #包括 #包括 #包括 #包括 #包括 静态std::位集散列; 静态void findSeed() { uint8_t c[7]; 常量自动查找冲突=[&](uint32\u t seed) { std::cout如果CRC(seed,dat)是dat的CRC,使用指定的seed,那么对于任何种子(s

我试图找到seed来散列最大可能长度的小写字母的短字符串,而不会发生冲突。 我选择了SSE 4.2 CRC32来简化任务。对于长度为4、5、6的种子,在某个合理的小值(我不能无限等待)内没有碰撞

#包括
#包括
#包括
#包括
#包括
静态std::位集散列;
静态void findSeed()
{
uint8_t c[7];
常量自动查找冲突=[&](uint32\u t seed)
{
std::cout如果
CRC(seed,dat)
dat
的CRC,使用指定的
seed
,那么对于任何种子(seed1,seed2)和匹配的数据长度对(dat1,dat2),以及给定的CRC(seed1,dat1),可以通过计算
CRC(seed1,dat1)
CRC(seed1,dat2)的异或来计算
CRC(seed1,dat1)
,和
CRC(seed2,dat2)

这反过来意味着,如果两条数据将为任何特定种子产生相同的CRC值,则它们将为每个可能的种子产生相同的值。如果对于任何
seed1
CRC(seed1,dat1a)
等于
CRC(seed1,dat1b)
,且字符串长度相等,则对于任何其他种子
seed2
和相同长度的数据
dat2
CRC(seed2,dat1a)
将等于
CRC(seed1,dat1a)xor CRC(seed1,dat2)xor CRC(seed2,dat2)
CRC(seed2,dat1b)
将等于
CRC(seed1,dat1b)xor CRC(seed2,dat2)
。由于XOR的所有三个项都相等,这意味着结果将同样相等。

如果
CRC(seed,dat)
dat的CRC,使用指定的
seed
,然后对任何种子(seed1,seed2)和匹配的数据长度对(dat1,dat2)以及给定的CRC(seed1,dat1),可以通过计算
CRC(seed1,dat1)
CRC(seed1,dat2)
CRC(seed2,dat2)
的异或来计算
CRC(seed2,dat1)


这反过来意味着,如果两条数据将为任何特定种子产生相同的CRC值,则它们将为每个可能的种子产生相同的值。如果对于任何
seed1
CRC(seed1,dat1a)
等于
CRC(seed1,dat1b)
,且字符串长度相等,则对于任何其他种子
seed2
和相同长度的数据
dat2
CRC(seed2,dat1a)
将等于
CRC(seed1,dat1a)xor CRC(seed1,dat2)xor CRC(seed2,dat2)
CRC(seed2,dat1b)
将等于
CRC(seed1,dat1b)xor CRC(seed2,dat2)
。由于XOR的所有三个项都相等,这意味着结果同样相等。

如另一个答案中所述,CRC对此无能为力。相反,您只需将六个或更少的小写字母编码为以26为基数的32位整数,并根据字符串的长度使用一些偏移量。26^n的和表示n=0到6小于2^32。实际上要小得多,因为它可以用29位编码。或者像Peter Cordes评论的那样,用30位和6个5位字段编码

不会有冲突。如果有用的话,可以对该整数应用32位CRC对位进行置乱,这样也不会有冲突


正如您所观察到的,不可能在32位中唯一地编码七个或七个以上的小写字符。

如另一个答案中所述,CRC对此无能为力。相反,您应该简单地将六个或六个以下的小写字母编码为以26为基数的32位整数,其中一些偏移量取决于字符串的长度。n=0的26^n之和到6小于2^32。实际上要少得多,因为它可以用29位编码。或者像彼得·科德斯评论的那样,用30位和6个5位字段

不会有冲突。如果有用的话,可以对该整数应用32位CRC对位进行置乱,这样也不会有冲突


正如您所观察到的,不可能在32位中唯一地编码七个或更多小写字符。

神圣嵌套蝙蝠侠。哇。您为什么会这样做?如果您的问题是关于格式,那么答案是“对于长度=长度+1的字符串,编辑和添加另一级别的嵌套更简单”。代码只是为了快速检查假设。神圣的嵌套蝙蝠侠。哇。你为什么会这样做?如果你的问题是关于格式,那么答案是“对于长度=长度+1的字符串,编辑和添加另一级别的嵌套更简单”。该代码仅用于快速检查假设。每个字母5位x 6=30位:您可以将6个字母转换为一个32位整数,并轻松解包5位字段。每个字母5位x 6=30位:您可以将6个字母转换为一个32位整数,并轻松解包5位字段。
#include <bitset>
#include <limits>
#include <iterator>
#include <iostream>

#include <x86intrin.h>

static std::bitset<size_t(std::numeric_limits<uint32_t>::max()) + 1> hashes;

static void findSeed()
{
    uint8_t c[7];
    const auto findCollision = [&] (uint32_t seed)
    {
        std::cout << "seed = " << seed << std::endl;
        hashes.reset();
        for (c[0] = 'a'; c[0] <= 'z'; ++c[0]) {
            uint32_t hash0 = _mm_crc32_u8(~seed, c[0]);
            for (c[1] = 'a'; c[1] <= 'z'; ++c[1]) {
                uint32_t hash1 = _mm_crc32_u8(hash0, c[1]);
                for (c[2] = 'a'; c[2] <= 'z'; ++c[2]) {
                    uint32_t hash2 = _mm_crc32_u8(hash1, c[2]);
                    for (c[3] = 'a'; c[3] <= 'z'; ++c[3]) {
                        uint32_t hash3 = _mm_crc32_u8(hash2, c[3]);
                        for (c[4] = 'a'; c[4] <= 'z'; ++c[4]) {
                            uint32_t hash4 = _mm_crc32_u8(hash3, c[4]);
                            for (c[5] = 'a'; c[5] <= 'z'; ++c[5]) {
                                uint32_t hash5 = _mm_crc32_u8(hash4, c[5]);
                                for (c[6] = 'a'; c[6] <= 'z'; ++c[6]) {
                                    uint32_t hash6 = _mm_crc32_u8(hash5, c[6]);
                                    if (hashes[hash6]) {
                                        std::cerr << "collision at ";
                                        std::copy(std::cbegin(c), std::cend(c), std::ostream_iterator<uint8_t>(std::cerr, ""));
                                        std::cerr << " " << hash6 << '\n';
                                        return;
                                    }
                                    hashes.set(hash6);
                                }
                            }
                        }
                    }
                }
            }
            std::cout << "c[0] = " << c[0] << std::endl;
        }
    };
    for (uint32_t seed = 0; seed != std::numeric_limits<uint32_t>::max(); ++seed) {
        findCollision(seed);
    }
    findCollision(std::numeric_limits<uint32_t>::max());
}

int main()
{
    findSeed();
}