2
\$\begingroup\$

I have the following implementation of the Fnv1a hashing for a string, which should be correct:

public static uint Fnv1a(string toHash, bool separateUpperByte = false)
{
    IEnumerable<byte> bytesToHash;

    if (separateUpperByte)
    {
        bytesToHash = toHash.ToCharArray().Select(c => new[] { (byte)((c - (byte)c) >> 8), (byte)c }).SelectMany(c => c);
    }
    else
    {
        bytesToHash = toHash.ToCharArray().Select(Convert.ToByte);
    }

    uint hash = FnvConstants.FnvOffset32;
    foreach (var chunk in bytesToHash)
    {
        hash ^= chunk;
        hash *= FnvConstants.FnvPrime32;
    }

    return hash;
}

I now want to hash Guids instead of strings. Will the following give a good fnv1 hash?

public static uint Fnv1a(Guid toHash, bool separateUpperByte = false)
{
    IEnumerable<byte> bytesToHash;
    if (separateUpperByte)
    {
        bytesToHash = toHash.ToByteArray().Select(c => new[] { (byte)((c - (byte)c) >> 8), (byte)c }).SelectMany(c => c);
    }
    else
    {
        bytesToHash = toHash.ToByteArray();
    }
    uint hash = FnvConstants.FnvOffset32;
    foreach (var chunk in bytesToHash)
    {
        hash ^= chunk;
        hash *= FnvConstants.FnvPrime32;
    }
    return hash;
}

We use the hash for determining partitions in a Service Fabric cluster. My concern is whether this implementation distributes the keys evenly.

\$\endgroup\$
  • 1
    \$\begingroup\$ It would seem to me that best reusability would be to reduce the second method to a one-liner: public static uint Fnv1aGuid(Guid toHash, bool separateUpperByte = false) => Fnv1a(toHash.ToString(), separateUpperByte); \$\endgroup\$ – Jesse C. Slicer Sep 29 '20 at 14:31
  • \$\begingroup\$ And considering that you can have the same method name with a different type of parameter, you can even leave off the "Guid" in Fnv1aGuid. Plus you could make it an extension method. \$\endgroup\$ – BCdotWEB Sep 29 '20 at 15:31
  • \$\begingroup\$ @JesseC.Slicer I am thinking that would hurt performance. In that case it would probably be better to store the Guids as strings instead. \$\endgroup\$ – yngling Sep 29 '20 at 23:39
  • \$\begingroup\$ @yngling if this is your performance bottleneck, I'd be extremely surprised. \$\endgroup\$ – Jesse C. Slicer Sep 30 '20 at 1:22
  • \$\begingroup\$ @JesseC.Slicer Well, when I say performance I am thinking compared with just using strings. If I want to convert to strings before hashing, I feel I might as well just store the Guids as strings, as hashing is about the only thing I do with them. \$\endgroup\$ – yngling Sep 30 '20 at 7:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.