我期待做一个自定义哈希表在C实现。GNU库中是否已经有MD5/SHA1散列函数,或者我必须使用外部库来实现?我想找的是:
int hashValue; hashValue = MD5_HASH(valToHash);
e0uiprwp1#
你可以看看Bob Jenkin对许多哈希函数的调查和分析:
或者只是将他的lookup3例程(他已经将其放入公共领域)放入您的项目中:
xfb7svmp2#
对于哈希表,您不需要加密强度,只需良好的随机化属性。破解的加密哈希函数(如MD5)很好,但您可能希望使用MD4,它更快,更简单,您可以直接在代码中包含实现。从规范中重写它并不难(因为你只需要一个哈希表的函数,所以如果你在某个时候弄错了,这并不是一个问题)。无耻的插头:在sphlib中有一个MD4的优化C实现。
idfiyjo83#
除非你已经有一个很好的理由使用MD5,否则你可能需要重新考虑。在哈希表中,什么是一个“好”的哈希函数很大程度上取决于你想要实现的目标。您可能想阅读Python的dictobject.c中的注解,以了解其他人所做的各种权衡。
dictobject.c
dw1jzc5e4#
有几个可信的、简单的版本可用--我在R的digest源代码中有几个。以下是我在DESCRIPTION文件中写的内容:产品描述:摘要包提供了使用md5,sha-1,sha-256和crc 32算法创建任意R对象的“散列”列表的功能,允许轻松比较R语言对象。罗恩Rivest的md5算法在RFC 1321中规定,SHA-1和SHA-256算法在FIPS-180-1和FIPS-180-2中规定,crc 32算法在ftp://ftp.rocksoft.com/cliens/rocksoft/papers/crc_v3.txt。对于md5、sha-1和sha-256,此软件包使用Christophe Devine提供的小型独立实现。对于crc 32,使用来自zlib库的代码。我认为Christophe的一些代码已经不在www.example.com上cr0.net,但是搜索应该会引导您找到其他几个包含它的项目。他的文件头很清楚:
/* * FIPS-180-1 compliant SHA-1 implementation, * by Christophe Devine <[email protected]>; * this program is licensed under the GPL. */
他的代码与参考输出相符
bwleehnv5#
Glibc的crypt()使用基于MD5的算法,如果salt以$1$开始。但是既然你提到你要做一个哈希表实现,也许Jenkins哈希会更合适。
crypt()
slhcrj9b6#
gcrypt和openssl可以做MD5,SHA和其他哈希,这里有一个libgcrypt的例子:
#include <gcrypt.h> #include <stdio.h> // compile gcc md5_test.c -lgcrypt int main(int argc, char *argv[]) { unsigned char digest[16]; char digest_ascii[32+1] = {0,}; int digest_length = gcry_md_get_algo_dlen (GCRY_MD_MD5); int i; printf("hashing=%s len=%d\n", argv[1], digest_length); gcry_md_hash_buffer(GCRY_MD_MD5, digest, argv[1], strlen(argv[1])); for (i=0; i < digest_length; i++) { sprintf(digest_ascii+(i*2), "%02x", digest[i]); } printf("hash=%s\n", digest_ascii); }
`
niknxzdl7#
OpenSSL库拥有您想要的所有加密例程,包括加密哈希。
p5fdfcr18#
Murmur3是一个快速的非加密算法,你可以使用。在这个线程https://softwareengineering.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed中可以找到murmur与其他算法的良好速度比较一种可能的实现方式:https://github.com/PeterScott/murmur3范例:
uint32_t hash; uint32_t seed = 42; char* input = "HelloWorld"; MurmurHash3_x86_32(input, strlen(input), seed, &hash); printf("x86_32: %08x\n", hash);
zbq4xfa09#
对于现代x86系统来说,CityHash 64可能总是一个不错的选择,尽管它并不总是最快的选择。对于少量的数据(~16字节),FarmHash 64可能是最快的选择,对于中等大小的数据(~128字节),CityHash 64可能是最快的一个,但是数据越大(~4KB),所有的东西就越有利于xxHash 64,最终将主导其他两个。大多数哈希表的键都很小,但如果你知道你的键总是很大,你也可以考虑xxHash 64。如果你的目标也是非x86系统(ARM、RISC-V、PowerPC)或较旧的x86 CPU(尤其是AMD的CPU),你肯定会更喜欢CityHash 64,因为上面提到的三种CPU在这些条件下的性能都会更差,但CityHash 64被证明比其他两种更稳定。有时FarmHash 64会是最快的非x86 CPU,但即使它击败了CityHash 64,它也是一个相对接近的选择,所以CityHash 64仍然是一个很好的选择。当目标是32位系统时,使用xxHash 32代替,也就是说,如果32位哈希值足够,对于32位,xxHash 32总是产生良好的结果,并且当哈希数据变得更大时,xxHash 32很快就主导了所有其他数据,已经开始在中等大小范围内。
如果你需要哈希表实现的哈希函数,这里有一个很好的候选者列表:
https://github.com/lemire/clhash
memcpy()
https://xxhash.com
https://github.com/google/cityhash
https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp
https://github.com/google/farmhash
https://www.burtleburtle.net/bob/c/lookup3.c
https://www.burtleburtle.net/bob/hash/spooky.htmlxxHash在首页上有一个基准比较,但它错过了clhash,并且它只包含三个MurMur 3变体中的一个(只有32位)。它还声称SpookHash只有64位,而实际上它是128位(当产生32/64位哈希时,它只是相应地缩短了128位值)。我不太信任那个表,我认为它被修改过,使xxHash看起来更上级。在一天结束的时候,没有明确的答案什么是最好的哈希使用。例如,在Core i7- 5820 K系统上并使用64位构建,xxHash 64在更大(0.5KB+)的数据大小上获胜,紧随其后的是64位FarmHash和CityHash;在较小的数据上,这三个总是非常接近,有时一个赢,有时另一个赢。在Phone SE(A9 CPU)上,使用64位进程,xxHash永远不会获胜,CityHash和FarmHash占主导地位。然而,在同一个系统中,在一个32位进程中,xxHash 32击败了其他进程。在Xbox One(AMD Jaguar 1.75GHz CPU)上,尽管使用SSE的x86,但CityHash和FarmHash在xxHash上占主导地位。
问题是,大多数现代哈希函数都是在考虑特定CPU的情况下编写的,对架构进行了假设,或者针对特定数据中心运营商(如Google或Facebook)的需求进行了优化,并且在按设计使用时会优于所有其他哈希函数,但当用于其他场景或其他平台时,结果可能完全不同。它们都具有出色的哈希质量,并且在实践中产生很少的冲突,所以这并不是使它们与众不同的原因。查看2016年的这篇博客文章,了解详细结果:https://aras-p.info/blog/2016/08/09/More-Hash-Function-Tests但有一件事是肯定的:它们都可以轻松地击败MD5,这比上面提到的任何一个都慢100倍,因为MD5被设计为加密安全,这需要比避免冲突所需的更难的混合。当然,MD5也希望避免冲突(两个不相关的数据片段同时产生相同的哈希值),但对于加密哈希函数来说,更重要的是无法反向哈希,这意味着,给定一个特定的哈希值,它必须不可能产生数据,当得到哈希时,将产生完全相同的值。如果你可以产生碰撞,那是非常糟糕的,并允许许多类型的攻击,这就是为什么MD5不再安全了(有一种已知的方法可以产生碰撞,而且非常快),但到今天为止,没有方法可以产生将哈希到给定值的数据,如果你可以做到这一点,所有的门都对你甚至可以想到的任何攻击开放。
9条答案
按热度按时间e0uiprwp1#
你可以看看Bob Jenkin对许多哈希函数的调查和分析:
或者只是将他的lookup3例程(他已经将其放入公共领域)放入您的项目中:
xfb7svmp2#
对于哈希表,您不需要加密强度,只需良好的随机化属性。破解的加密哈希函数(如MD5)很好,但您可能希望使用MD4,它更快,更简单,您可以直接在代码中包含实现。从规范中重写它并不难(因为你只需要一个哈希表的函数,所以如果你在某个时候弄错了,这并不是一个问题)。无耻的插头:在sphlib中有一个MD4的优化C实现。
idfiyjo83#
除非你已经有一个很好的理由使用MD5,否则你可能需要重新考虑。在哈希表中,什么是一个“好”的哈希函数很大程度上取决于你想要实现的目标。您可能想阅读Python的
dictobject.c
中的注解,以了解其他人所做的各种权衡。dw1jzc5e4#
有几个可信的、简单的版本可用--我在R的digest源代码中有几个。以下是我在DESCRIPTION文件中写的内容:
产品描述:摘要包提供了使用md5,sha-1,sha-256和crc 32算法创建任意R对象的“散列”列表的功能,允许轻松比较R语言对象。罗恩Rivest的md5算法在RFC 1321中规定,SHA-1和SHA-256算法在FIPS-180-1和FIPS-180-2中规定,crc 32算法在
ftp://ftp.rocksoft.com/cliens/rocksoft/papers/crc_v3.txt。对于md5、sha-1和sha-256,此软件包使用Christophe Devine提供的小型独立实现。对于crc 32,使用来自zlib库的代码。
我认为Christophe的一些代码已经不在www.example.com上cr0.net,但是搜索应该会引导您找到其他几个包含它的项目。他的文件头很清楚:
他的代码与参考输出相符
bwleehnv5#
Glibc的
crypt()
使用基于MD5的算法,如果salt以$1$开始。但是既然你提到你要做一个哈希表实现,也许Jenkins哈希会更合适。slhcrj9b6#
gcrypt和openssl可以做MD5,SHA和其他哈希,这里有一个libgcrypt的例子:
`
niknxzdl7#
OpenSSL库拥有您想要的所有加密例程,包括加密哈希。
p5fdfcr18#
Murmur3是一个快速的非加密算法,你可以使用。
在这个线程https://softwareengineering.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed中可以找到murmur与其他算法的良好速度比较
一种可能的实现方式:https://github.com/PeterScott/murmur3
范例:
zbq4xfa09#
tl;dr Answer
对于现代x86系统来说,CityHash 64可能总是一个不错的选择,尽管它并不总是最快的选择。对于少量的数据(~16字节),FarmHash 64可能是最快的选择,对于中等大小的数据(~128字节),CityHash 64可能是最快的一个,但是数据越大(~4KB),所有的东西就越有利于xxHash 64,最终将主导其他两个。大多数哈希表的键都很小,但如果你知道你的键总是很大,你也可以考虑xxHash 64。
如果你的目标也是非x86系统(ARM、RISC-V、PowerPC)或较旧的x86 CPU(尤其是AMD的CPU),你肯定会更喜欢CityHash 64,因为上面提到的三种CPU在这些条件下的性能都会更差,但CityHash 64被证明比其他两种更稳定。有时FarmHash 64会是最快的非x86 CPU,但即使它击败了CityHash 64,它也是一个相对接近的选择,所以CityHash 64仍然是一个很好的选择。
当目标是32位系统时,使用xxHash 32代替,也就是说,如果32位哈希值足够,对于32位,xxHash 32总是产生良好的结果,并且当哈希数据变得更大时,xxHash 32很快就主导了所有其他数据,已经开始在中等大小范围内。
完整答案
如果你需要哈希表实现的哈希函数,这里有一个很好的候选者列表:
https://github.com/lemire/clhash
memcpy()
复制原始字节更快(当然,只有当要哈希的数据当前在CPU缓存中时才有效)。不像大多数其他散列,它使用了很多位移位逻辑指令,这个散列在很大程度上是基于乘法数字,现代CPU可以做得很快,但与旧的CityHash可能会提供更好的性能。https://xxhash.com
https://github.com/google/cityhash
https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp
https://github.com/google/farmhash
https://www.burtleburtle.net/bob/c/lookup3.c
https://www.burtleburtle.net/bob/hash/spooky.html
xxHash在首页上有一个基准比较,但它错过了clhash,并且它只包含三个MurMur 3变体中的一个(只有32位)。它还声称SpookHash只有64位,而实际上它是128位(当产生32/64位哈希时,它只是相应地缩短了128位值)。我不太信任那个表,我认为它被修改过,使xxHash看起来更上级。
在一天结束的时候,没有明确的答案什么是最好的哈希使用。例如,在Core i7- 5820 K系统上并使用64位构建,xxHash 64在更大(0.5KB+)的数据大小上获胜,紧随其后的是64位FarmHash和CityHash;在较小的数据上,这三个总是非常接近,有时一个赢,有时另一个赢。在Phone SE(A9 CPU)上,使用64位进程,xxHash永远不会获胜,CityHash和FarmHash占主导地位。然而,在同一个系统中,在一个32位进程中,xxHash 32击败了其他进程。在Xbox One(AMD Jaguar 1.75GHz CPU)上,尽管使用SSE的x86,但CityHash和FarmHash在xxHash上占主导地位。
问题是,大多数现代哈希函数都是在考虑特定CPU的情况下编写的,对架构进行了假设,或者针对特定数据中心运营商(如Google或Facebook)的需求进行了优化,并且在按设计使用时会优于所有其他哈希函数,但当用于其他场景或其他平台时,结果可能完全不同。它们都具有出色的哈希质量,并且在实践中产生很少的冲突,所以这并不是使它们与众不同的原因。
查看2016年的这篇博客文章,了解详细结果:
https://aras-p.info/blog/2016/08/09/More-Hash-Function-Tests
但有一件事是肯定的:它们都可以轻松地击败MD5,这比上面提到的任何一个都慢100倍,因为MD5被设计为加密安全,这需要比避免冲突所需的更难的混合。当然,MD5也希望避免冲突(两个不相关的数据片段同时产生相同的哈希值),但对于加密哈希函数来说,更重要的是无法反向哈希,这意味着,给定一个特定的哈希值,它必须不可能产生数据,当得到哈希时,将产生完全相同的值。如果你可以产生碰撞,那是非常糟糕的,并允许许多类型的攻击,这就是为什么MD5不再安全了(有一种已知的方法可以产生碰撞,而且非常快),但到今天为止,没有方法可以产生将哈希到给定值的数据,如果你可以做到这一点,所有的门都对你甚至可以想到的任何攻击开放。