Skip to content

Instantly share code, notes, and snippets.

@DurtyFree
Last active January 9, 2020 14:22
Show Gist options
  • Save DurtyFree/eb9498eaf23ebe6128b96a0746ef6727 to your computer and use it in GitHub Desktop.
Save DurtyFree/eb9498eaf23ebe6128b96a0746ef6727 to your computer and use it in GitHub Desktop.
Pokemon Go PokeMobBot niantic hashing
internal static class HashConstants
{
#region Constants
/*
#if 1
// IOS 1.13.3
static uint64_t magic_table[16] = {
0x95C05F4D1512959E, 0xE4F3C46EEF0DCF07,
0x6238DC228F980AD2, 0x53F3E3BC49607092,
0x4E7BE7069078D625, 0x1016D709D1AD25FC,
0x044E89B8AC76E045, 0xE0B684DDA364BFA1,
0x90C533B835E89E5F, 0x3DAF462A74FA874F,
0xFEA54965DD3EF5A0, 0x287A5D7CCB31B970,
0xAE681046800752F8, 0x121C2D6EAF66EC6E,
0xEE8F8CA7E090FB20, 0xCE1AE25F48FE0A52,
};
#define ROUND_MAGIC U128(0x78F32468CD48D6DE,0x14C983660183C0AE)
#define FINAL_MAGIC0 0xBDB31B10864F3F87
#define FINAL_MAGIC1 0x5B7E9E828A9B8ABD
#endif
#if 0
// Android 0.43.4
static uint64_t magic_table[16] = {
0x48CD0D725609F95F, 0x25D4A39B5ACB4330,
0x1C0C27978A3649A3, 0x5C7068B9C51C5E4B,
0x69A054CBE1369106, 0x4C318ED6A12B9645,
0xC751EECD2715C836, 0xAAEDCC7A92014B7A,
0xE91DB51D36F47460, 0x78EA4A974D9157B8,
0xE4E65C1A929E8AB1, 0x6BC61BB9C5988769,
0x78C7794B899D8819, 0xB338727B9C7600F7,
0x26BA60FCB9EDC151, 0xE7D74B3CD6293E6B,
};
#define ROUND_MAGIC U128(0x1A32C90D816A2F1F,0x76327D13FD037D57)
#define FINAL_MAGIC0 0x106245053E723AD8
#define FINAL_MAGIC1 0x1CDA65FFA125C8F6
#endif
#if
// Android 0.41.4
static uint64_t magic_table[16] = {
0x475BD60F17CE7238, 0xC11B0E0066794E31,
0x75F5BD04F566D70C, 0x09F4F46E7CEC785C,
0x6A52B40820F5EBFF, 0x27F300DB7195A066,
0xBDFDE4DAC75939BF, 0xF7F239CFD77A36AB,
0x7013DEFA151CD579, 0x8864183CFD4C24F9,
0x21C426C79EA1445A, 0xB188FEAE415747BA,
0x127421C8D0BD9352, 0x8C7E6FC0526AD558,
0x7E33F449C404A71A, 0xE955B7D15DE757DC,
};
#define ROUND_MAGIC U128(0x232B242A99C10878,0x667EFDF872801CD8)
#define FINAL_MAGIC0 0xF6AC14F2D12AB0C1
#define FINAL_MAGIC1 0x101FF0340EC93F87
#endif
*/
#endregion
public const ulong FinalMagic0 = 0x106245053E723AD8;
public const ulong FinalMagic1 = 0x1CDA65FFA125C8F6;
public static UInt128 RoundMagic = new UInt128(0x1A32C90D816A2F1F, 0x76327D13FD037D57);
public static readonly ulong[] MagicTable = {
0x48CD0D725609F95F, 0x25D4A39B5ACB4330,
0x1C0C27978A3649A3, 0x5C7068B9C51C5E4B,
0x69A054CBE1369106, 0x4C318ED6A12B9645,
0xC751EECD2715C836, 0xAAEDCC7A92014B7A,
0xE91DB51D36F47460, 0x78EA4A974D9157B8,
0xE4E65C1A929E8AB1, 0x6BC61BB9C5988769,
0x78C7794B899D8819, 0xB338727B9C7600F7,
0x26BA60FCB9EDC151, 0xE7D74B3CD6293E6B,
};
}
public class NiaHash
{
static ulong read_int64(byte[] p, int offset)
{
return BitConverter.ToUInt64(p, offset);
}
public static ulong compute_hash(byte[] input, uint len)
{
uint numChunks = len / 128;
// copy tail, pad with zeroes
byte[] tail = new byte[128];
uint tailSize = len % 128;
Array.Copy(input, len - tailSize, tail, 0, tailSize);
UInt128 hash;
if (numChunks != 0) hash = hash_chunk(input, 128, 0);
else hash = hash_chunk(tail, tailSize, 0);
hash += HashConstants.RoundMagic;
int offset = 0;
if (numChunks != 0)
{
while (--numChunks > 0)
{
offset += 128;
hash = hash_muladd(hash, HashConstants.RoundMagic, hash_chunk(input, 128, offset));
}
if (tailSize > 0)
{
hash = hash_muladd(hash, HashConstants.RoundMagic, hash_chunk(tail, tailSize, 0));
}
}
hash += new UInt128(tailSize * 8, 0);
if (hash > new UInt128(0x7fffffffffffffff, 0xffffffffffffffff)) hash++;
hash = hash << 1 >> 1;
ulong x = hash.Hi + (hash.Lo >> 32);
x = ((x + (x >> 32) + 1) >> 32) + hash.Hi;
ulong y = (x << 32) + hash.Lo;
ulong a = x + HashConstants.FinalMagic0;
if (a < x) a += 0x101;
ulong b = y + HashConstants.FinalMagic1;
if (b < y) b += 0x101;
UInt128 h = new UInt128(a) * b;
UInt128 mul = new UInt128(0x101);
h = (mul * h.Hi) + h.Lo;
h = (mul * h.Hi) + h.Lo;
if (h.Hi > 0) h += mul;
if (h.Lo > 0xFFFFFFFFFFFFFEFE) h += mul;
return h.Lo;
}
private static UInt128 hash_chunk(byte[] chunk, long size, int off)
{
UInt128 hash = new UInt128(0);
for (int i = 0; i < 8; i++)
{
int offset = i * 16;
if (offset >= size) break;
ulong a = read_int64(chunk, off + offset);
ulong b = read_int64(chunk, off + offset + 8);
hash += (new UInt128(a + HashConstants.MagicTable[i * 2])) * (new UInt128(b + HashConstants.MagicTable[i * 2 + 1]));
}
return hash << 2 >> 2;
}
private static UInt128 hash_muladd(UInt128 hash, UInt128 mul, UInt128 add)
{
ulong a0 = add.Lo & 0xffffffff,
a1 = add.Lo >> 32,
a23 = add.Hi;
ulong m0 = mul.Lo & 0xffffffff,
m1 = mul.Lo >> 32,
m2 = mul.Hi & 0xffffffff,
m3 = mul.Hi >> 32;
ulong h0 = hash.Lo & 0xffffffff,
h1 = hash.Lo >> 32,
h2 = hash.Hi & 0xffffffff,
h3 = hash.Hi >> 32;
ulong c0 = (h0 * m0),
c1 = (h0 * m1) + (h1 * m0),
c2 = (h0 * m2) + (h1 * m1) + (h2 * m0),
c3 = (h0 * m3) + (h1 * m2) + (h2 * m1) + (h3 * m0),
c4 = (h1 * m3) + (h2 * m2) + (h3 * m1),
c5 = (h2 * m3) + (h3 * m2),
c6 = (h3 * m3);
ulong r2 = c2 + (c6 << 1) + a23,
r3 = c3 + (r2 >> 32),
r0 = c0 + (c4 << 1) + a0 + (r3 >> 31),
r1 = c1 + (c5 << 1) + a1 + (r0 >> 32);
ulong res0 = ((r3 << 33 >> 1) | (r2 & 0xffffffff)) + (r1 >> 32);
return new UInt128(res0, (r1 << 32) | (r0 & 0xffffffff));
}
}
public struct UInt128
{
public ulong Hi, Lo;
#region constructors
public UInt128(ulong high, ulong low)
{
Hi = high; Lo = low;
}
public UInt128(ulong low)
{
Hi = 0; Lo = low;
}
#endregion
#region comparators
public bool Equals(UInt128 other)
{
return (Hi == other.Hi && Lo == other.Lo);
}
public static bool operator >(UInt128 a, UInt128 b)
{
if (a.Hi == b.Hi) return a.Lo > b.Lo;
return a.Hi > b.Hi;
}
public static bool operator <(UInt128 a, UInt128 b)
{
if (a.Hi == b.Hi) return a.Lo < b.Lo;
return a.Hi < b.Hi;
}
#endregion
#region arithmetic
public static UInt128 operator ++(UInt128 a)
{
a.Lo++;
if (a.Lo == 0) a.Hi++;
return a;
}
public static UInt128 operator +(UInt128 a, UInt128 b)
{
ulong c = (((a.Lo & b.Lo) & 1) + (a.Lo >> 1) + (b.Lo >> 1)) >> 63;
return new UInt128(a.Hi + b.Hi + c, a.Lo + b.Lo);
}
public static UInt128 operator +(UInt128 a, ulong b)
{
return a + new UInt128(b);
}
public static UInt128 operator -(UInt128 a, UInt128 b)
{
ulong l = a.Lo - b.Lo;
ulong c = (((l & b.Lo) & 1) + (b.Lo >> 1) + (l >> 1)) >> 63;
return new UInt128(a.Hi - (b.Hi + c), l);
}
#endregion
#region bitwise operations
public static UInt128 operator &(UInt128 a, UInt128 b)
{
return new UInt128(a.Hi & b.Hi, a.Lo & b.Lo);
}
public static UInt128 operator <<(UInt128 a, int b)
{
a.Hi <<= b;
a.Hi |= (a.Lo >> (64 - b));
a.Lo <<= b;
return a;
}
public static UInt128 operator >>(UInt128 a, int b)
{
a.Lo >>= b;
a.Lo |= (a.Hi << (64 - b));
a.Hi >>= b;
return a;
}
#endregion
#region multiplication
private static UInt128 M64(ulong a, ulong b)
{
ulong a1 = (a & 0xffffffff), b1 = (b & 0xffffffff),
t = (a1 * b1), w3 = (t & 0xffffffff), k = (t >> 32);
a >>= 32;
t = (a * b1) + k;
k = (t & 0xffffffff);
var w1 = (t >> 32);
b >>= 32;
t = (a1 * b) + k;
k = (t >> 32);
return new UInt128((a * b) + w1 + k, (t << 32) + w3);
}
public static UInt128 operator *(UInt128 a, int b)
{
return a * (ulong)b;
}
public static UInt128 operator *(UInt128 a, ulong b)
{
UInt128 ans = M64(a.Lo, b);
ans.Hi += (a.Hi * b);
return ans;
}
public static UInt128 operator *(UInt128 a, UInt128 b)
{
UInt128 ans = M64(a.Lo, b.Lo);
ans.Hi += (a.Hi * b.Lo) + (a.Lo * b.Hi);
return ans;
}
#endregion
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment