pkNX/pkNX.Containers/Misc/FnvHashDecoder.cs
2022-10-17 13:00:16 +02:00

128 lines
3.8 KiB
C#

using pkNXHashDecoder;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace pkNX.Containers;
public class FnvHashDecoder
{
public const string AllowedChars = "etaoinshrdlcumw_0123456789fgypbvkjxqz/."; // Sorted by most common first
public HashSet<ulong> HashesToTest = new() { 9252365659083253459, 17205188591700921149, 1234775724179408742 };
// 64 bit implementation
private const ulong kFnvPrime_64 = 0x00000100000001b3;
private const ulong kOffsetBasis_64 = 0xCBF29CE484222645;
public Dictionary<ulong, string> FoundKeys = new();
public Dictionary<ulong, string> Run(int minLength, int maxLength)
{
Debug.Assert(FnvHash.HashFnv1a_64("stickyball") == 0x15cb1f582d2b05ab);
Debug.Assert(FnvHash.HashFnv1a_64("enigma") == 0xC75DDBE25402B11C);
var tasks = new List<Task>();
for (int i = 0; i < FnvHashDecoderLib.AllowedCharCount; ++i)
{
int startChar = i;
tasks.Add(Task.Run(() =>
{
var dict = FnvHashDecoderLib.StartDecoding(15, startChar, "pm0025_");
if (dict.Count != 0)
{
foreach (var x in dict)
{
FoundKeys.TryAdd(x.Key, x.Value);
Debug.WriteLine($"{x.Key} {x.Value}");
}
}
//StartLoop(length, startChar);
}));
}
Task t = Task.WhenAll(tasks);
try
{
t.Wait();
}
catch { }
return FoundKeys;
}
/*private void StartLoop(int length, int startChar)
{
Span<char> chars = stackalloc char[length];
Span<byte> allowedCharIndex = stackalloc byte[length]; // Current AllowedChar
// Reset all chars to starting point
chars[0] = AllowedChars[startChar];
allowedCharIndex[0] = (byte)startChar;
for (int i = 1; i < length; i++)
chars[i] = AllowedChars[0];
while (allowedCharIndex[0] == startChar)
{
// Build the hash of all chars except the last one
ulong hashBase = kOffsetBasis_64;
for (int i = 0; i < length - 1; ++i)
{
hashBase ^= chars[i];
hashBase *= kFnvPrime_64;
// Automatically test for shorter length strings
if (hashBase == 9252365659083253459)
{
FoundKeys.Add(hashBase, new string(chars[0..i]));
}
}
// Loop through all AllowedChars
for (int j = 0; j < AllowedChars.Length; ++j)
{
ulong hash = hashBase;
hash ^= AllowedChars[j];
hash *= kFnvPrime_64;
if (hash == 9252365659083253459)
{
chars[length - 1] = AllowedChars[j];
FoundKeys.Add(hash, new string(chars));
}
}
int carry = 0;
int c = length - 2;
for (; c >= 0; c--)
{
++allowedCharIndex[c];
carry = allowedCharIndex[c] / AllowedChars.Length;
allowedCharIndex[c] %= (byte)AllowedChars.Length;
chars[c] = AllowedChars[allowedCharIndex[c]];
if (carry == 0)
break;
}
// Reached the end
if (carry != 0 && c == 0)
break;
// Already found all keys
if (FoundKeys.Count != 0)
return;
}
}*/
}