Lightweight 8 byte hash function algorithm

后端 未结 4 2210
旧巷少年郎
旧巷少年郎 2021-01-02 13:27

I need to extract an 8 byte digest from a variable length string so I\'m looking for such an algorithm that I will implement in c/c++. That will be part of a digital signatu

相关标签:
4条回答
  • 2021-01-02 14:04

    Here is a modified version of a 32 bit version I found in my old source files

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

    But hashing will always result in collisions. Of course some algorithms are better than others.

    Edit: I found the source of the 32 bit version: http://www.cse.yorku.ca/~oz/hash.html

    0 讨论(0)
  • 2021-01-02 14:07

    There is no chance to do a secure hash in 64 bits. Even SHA-1 at 160 bit is considered theoretically broken. You should use SHA2-256 if you really care about secure digital signing. If you don't care about security and just want a hash function that avoids non-adversarial collisions just use the following, it is fine:

    constexpr uint64 P1 = 7;
    constexpr uint64 P2 = 31;
    
    uint64 hash = P1;
    for (const char* p = s; *p != 0; p++) {
        hash = hash * P2 + *p;
    }
    
    0 讨论(0)
  • 2021-01-02 14:08

    As AndrewTomazos-Fathomling said, it's impossible to do a secure hash in 64 bits, so if that's your intention then my advice is STOP, pick up a book and read about cryptographically secure hashing.

    If you don't plan on using this as a secure hash and you do not care about collisions or attacks, then the answer he gave you works just fine and you can tweak the primes P1 and P2 as necessary. I will give you another alternative which allows you to do tagged hashing and mixes things up more.

    // 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);
    }
    
    0 讨论(0)
  • 2021-01-02 14:20

    I had the exact same requirement, and I settled for FNV-1A, after dismissing SIP hash (implemented by bloomberg here).

    I found an FNV implementation here:

    https://github.com/foonathan/string_id/blob/master/hash.hpp

    which is:

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

    It appears he is looping using tail recursion. And stop condition is the null byte.
    (boost uses hash_range which is hash_combining each element in chain I guess.)

    License is zlib and copyright is Jonathan Müller. Though I'm not convinced a oneliner can be legally licensed if it implements research by other persons (Fowler-Noll-Vo).

    0 讨论(0)
提交回复
热议问题