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\$
5
  • 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\$ Commented Sep 29, 2020 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
    Commented Sep 29, 2020 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
    Commented Sep 29, 2020 at 23:39
  • \$\begingroup\$ @yngling if this is your performance bottleneck, I'd be extremely surprised. \$\endgroup\$ Commented Sep 30, 2020 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
    Commented Sep 30, 2020 at 7:29

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.