使用SuperFastHash而不是CRC32?

时间:2011-09-05 20:29:19

标签: c hash crc

注意:我不是试图使用SuperFastHash并期望它提供与CRC32相同的输出值。

我正在编写一个简单的LZSS压缩/解压缩例程,以便在解压缩时提供非常快速的解压缩和无内存开销。输入数据被分成长度为4096字节的块,并按顺序压缩。

我的问题:我想为每个压缩块添加一些错误检测(块大小<= 4096字节)。时间约束是激烈的,因此校验和例程必须非常快。我避免使用加密算法(MD5,SHA1),因为它们涉及大量计算,我选择了CRC32(一种更简单明了的算法)。

经过一些测试后,我发现CRC32在项目限制方面太慢了。我使用了来自here的enwik9(维基百科的10 ^ 9字节文本转储)。我使用LZSS例程压缩它并获得570Mb文件。我测量了以下持续时间(单线程,磁盘IO排除,处理前加载到内存中的所有数据,平均10次试验):

|          Operation            |  Time (GCC4.4.5/Linux)   |  Time (MSVC2010/Win7)  |
|-------------------------------+--------------------------+------------------------|
|        Decompression          |        6.8 seconds       |      6.95 seconds      |
|  CRC32 on decompressed result |        4.9 seconds       |      4.62 seconds      |
|   CRC32 on compressed result  |        2.8 seconds       |      2.69 seconds      |

然后我只是好奇地测试了SuperFastHash:

|          Operation            |  Time (GCC4.4.5/Linux)   |  Time (MSVC2010/Win7)  |
|-------------------------------+--------------------------+------------------------|
|  SFH on decompressed result   |        1.1 seconds       |      1.33 seconds      |
|   SFH on compressed result    |        0.7 seconds       |      0.75 seconds      |

这是我的CRC32实现(我按照以下文档中的描述:http://www.ross.net/crc/download/crc_v3.txt):

# include <stdint.h>

// CRC32 lookup table (corresponding to the polynom 0x04C11DB7)
static const uint32_t  crc32_lookup_table[256] =
{
    0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
    0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
    0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
    // many lines skipped
    // ...
    0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
} ;

uint32_t crc32_hash(const uint8_t * data, size_t len)
{
    uint32_t crc32_register = 0xFFFFFFFF ;
    while( len-- )
    {
        crc32_register = (crc32_register >> 8)
                       ^ crc32_lookup_table[(crc32_register & 0x000000FF) ^ *data++] ;
    }
    return crc32_register ^ 0xFFFFFFFF ;
}

我的问题是:

我可以使用哈希而不是循环冗余校验值来在压缩数据块中执行错误检测吗?据我所知(我记得我的电子课程),CRC算法的设计就是这样 当数据通过噪声通道传输时,突发中发生错误时效率非常高,这不是从硬盘驱动器读取数据的情况。如果我错了,请纠正我。

感谢您的任何建议!

3 个答案:

答案 0 :(得分:3)

已经发现SuperFastHash存在一些问题,以及快速哈希函数murmur2。如果您正在寻找针对具有低冲突的更大数据块进行调整的内容,您可以尝试使用谷歌城市哈希(http://code.google.com/p/cityhash/)或murmur3的128位变体。除了crap8和crapwow之外还有一些声称可以提供几乎完美的位雪崩和漏斗并因此几乎没有碰撞,你可以在这里阅读它和其他非加密哈希函数:http://www.team5150.com/~andrew/noncryptohashzoo/

答案 1 :(得分:1)

即使对输入进行非常小的改动,哈希也会导致结果发生很大变化。

我认为SuperFastHash具有这种特性。它可能更容易受到冲突(因为它似乎很少被社区分析),但它不应该阻止您的使用。

祝你好运:)

答案 2 :(得分:1)

由于您的问题与安全无关,因此您可以使用“破坏”的加密哈希函数,这些函数对于有感染的攻击者并不安全,但仍然非常擅长检测传输错误。我正在考虑MD4,在某些平台上测量的速度比CRC32快。您可能还想查看RadioGatún和Panama;有关各种加密哈希函数的C和Java中的开源实现,请参阅this library

如果你的目标体系结构是一个最新的/足够大的x86 CPU,其中包含AES-NI指令,那么只需使用块密码AES计算CBC-MAC,就可以制作出非常快速且非常好的校验和。传统密钥(例如全零密钥);因为这不是为了安全,你甚至可以使用比标准AES少的轮次(例如5轮而不是标准的10轮)。