我需要从可变长度字符串中提取一个8字节的摘要,所以我正在寻找一种我将在c / c ++中实现的算法。这将是微控制器上数字签名程序的一部分,因此它必须是:
我查看了现有的算法,例如crc64,但它们对我的平台来说似乎太重了。
答案 0 :(得分:8)
没有机会以64位进行安全散列。即使是160位的SHA-1也被认为在理论上被破坏了。如果您真的关心安全数字签名,则应使用SHA2-256。如果您不关心安全性并且只想要一个避免非对抗性冲突的哈希函数,那么只需使用以下内容即可:
constexpr uint64 P1 = 7;
constexpr uint64 P2 = 31;
uint64 hash = P1;
for (const char* p = s; *p != 0; p++) {
hash = hash * P2 + *p;
}
答案 1 :(得分:3)
以下是我在旧源文件中找到的32位版本的修改版本
static unsigned long long llhash(const char *str)
{
unsigned long long hash = 5381;
int c;
while (c = *str++)
hash = ((hash << 5) + hash) + c;
return hash;
}
但是散列总是会导致碰撞。当然,有些算法比其他算法更好。
修改强> 我找到了32位版本的来源:http://www.cse.yorku.ca/~oz/hash.html
答案 2 :(得分:2)
正如AndrewTomazos-Fathomling所说,用64位进行安全散列是不可能的,所以如果这是你的意图,那么我的建议是停止,拿起一本书并阅读有关加密安全散列的内容。
如果您不打算将此作为安全哈希并且不关心碰撞或攻击,那么他给你的答案就可以了,你可以根据需要调整素数P1和P2。我将为您提供另一种替代方案,允许您进行标记哈希并将其混合起来。
// Disclaimer: I make no claims about the quality of this particular hash - it's
// certainly not a cryptographically secure hash, nor should it *ever* be
// construed as such.
unsigned long long quickhash64(const char *str, unsigned long long mix = 0)
{ // set 'mix' to some value other than zero if you want a tagged hash
const unsigned long long mulp = 2654435789;
mix ^= 104395301;
while(*str)
mix += (*str++ * mulp) ^ (mix >> 23);
return mix ^ (mix << 37);
}
答案 3 :(得分:1)
我有完全相同的要求,在解雇SIP哈希(implemented by bloomberg here)后,我选择 FNV-1A ,。
我在这里找到了一个FNV实现:
https://github.com/foonathan/string_id/blob/master/hash.hpp
是:
constexpr uint64_t fnv_basis = 14695981039346656037ull;
constexpr uint64_t fnv_prime = 1099511628211ull;
// FNV-1a 64 bit hash of null terminated buffer
uint64_t fnv1a_hash(const char* str, uint64_t hash = fnv_basis)
{
return *str ? fnv1a_hash(str + 1, (hash ^ *str) * fnv_prime) : hash;
}
看起来他正在使用尾递归进行循环。停止条件是null
字节
(boost使用hash_range
,我认为链中的每个元素都是hash_combining
。)
许可证 zlib ,版权归JonathanMüller所有。虽然我不相信如果一个oneliner实施了其他人的研究(Fowler-Noll-Vo),它就可以获得合法许可。