byte[] to 0x hex string with fnv1a32

3

I am trying to port the following python code to c#

import os
import sys
import ctypes

FNV32_PRIME = 0xB3CB2E29
FNV32_BASIS = 0x319712C3

def uint32(v):
  return ctypes.c_uint32(v).value

def fnv1a_hash(data):
  hval = FNV32_BASIS

  for i in range(0, len(data)):
    hval = uint32(hval ^ data[i])
    hval = uint32(hval * FNV32_PRIME)

  return hval

print("starting")

if len(sys.argv) == 2:
  input_file_path = sys.argv[1]
else: input_file_path = "dvars.txt"

with open(input_file_path, "r") as input_file:
    for dvar_name in input_file:
      dvar_name = dvar_name.rstrip("\r\n")
      dvar_hash_1 = dvar_name.lower() + '\x00'
      dvar_hash_2 = bytearray(dvar_hash_1.encode("ascii"))
      dvar_hash = fnv1a_hash(dvar_hash_2)
      final = "%-30s = 0x%08X" % (dvar_name, dvar_hash)
      print(final)
print("done")

which works fine:

starting
con_gameMsgWindow0MsgTime      = 0xFC60C821

I got this so far:

    public static class Extensions
    {
        private const UInt32 FnvPrime = 0xB3CB2E29;private const UInt32 FnvOffsetBasis = 0x319712C3;
        public static string ToHashFnv1a32(this string text, Fnv1a32 hasher = null)
        {
            var bytes_encoded = Encoding.UTF8.GetBytes(text); // +'\x00'
            if (hasher is null) hasher = new Fnv1a32(fnvPrime: FnvPrime, fnvOffsetBasis: FnvOffsetBasis);
            var byte_hash = hasher.ComputeHash(bytes_encoded);
            // int decValue = int.Parse(t, System.Globalization.NumberStyles.HexNumber);
            var uint32 = BitConverter.ToUInt32(byte_hash, 0);
            var uint32_hex = string.Format("{0:X}", uint32);
            var uint32_dec = string.Format("{0:D}", uint32);
            var stringg = BitConverter.ToString(byte_hash).Replace("-", "");
            var expected_hex = string.Format("{0:X}", 0xFC60C821);
            var expected_dec = string.Format("{0:D}", 0xFC60C821);
            return byte_hash.ToString(); // 
        }
    }

but for some reason i get the weirdest results:

    text    "con_gameMsgWindow0LineCount"   string
    hasher  {Fnv1a.Fnv1a32} Fnv1a.Fnv1a32
    bytes_encoded   {byte[0x0000001b]}  byte[]
    byte_hash   {byte[0x00000004]}  byte[]
    uint32  0x0a65c1a8  uint
    uint32_hex  "A65C1A8"   string
    uint32_dec  "174440872" string
    stringg "A8C1650A"  string
    expected_hex    "FC60C821"  string
    expected_dec    "4234201121"    string

I really am bumping my head on the table because i can't seem to figure out why it isn't calculating the right hash (i am using a modified version of https://github.com/jslicer/FNV-1a to allow me changing the base and offset)

c#
hash
asked on Stack Overflow Sep 22, 2019 by Bluescream • edited Sep 22, 2019 by Uwe Keim

1 Answer

2

The FNV1a-hash itself works in the C#-code. However, the C#-code differs from the Python-code in the following points regarding the processing of the input data:

  • The C#-code doesn't remove \r\n at the end.
  • The C#-code doesn't convert to lowercase letters.
  • No 0-byte is appended in the C#-code.

Additionally, the C#-code doesn't use the text con_gameMsgWindow0MsgTime, but con_gameMsgWindow0LineCount.

The solution is to add the following line at the beginning of the ToHashFnv1a32-method of the C#-code:

text = text.TrimEnd('\r', '\n').ToLower() + "\0";

and of course the same data must be used in both codes for the test.

Note: The prime and offset basis used in the Python-code differ from the commonly used values.

answered on Stack Overflow Sep 22, 2019 by Topaco • edited Sep 22, 2019 by Topaco

User contributions licensed under CC BY-SA 3.0