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.
public static uint Fnv1aGuid(Guid toHash, bool separateUpperByte = false) => Fnv1a(toHash.ToString(), separateUpperByte);
\$\endgroup\$Fnv1aGuid
. Plus you could make it an extension method. \$\endgroup\$