110 lines
2.7 KiB
Python
110 lines
2.7 KiB
Python
|
|
from math import gcd
|
||
|
|
from random import randint, randbytes
|
||
|
|
|
||
|
|
H = 18446744073709551614
|
||
|
|
K = 59275109328752
|
||
|
|
M = 2**64
|
||
|
|
|
||
|
|
def Rjb(j: int, b: int) -> int:
|
||
|
|
return b << j**2
|
||
|
|
|
||
|
|
def Rb(b: int) -> int:
|
||
|
|
Rb = 0
|
||
|
|
for j in range(8):
|
||
|
|
Rb ^= Rjb(j, b)
|
||
|
|
return Rb
|
||
|
|
|
||
|
|
'''
|
||
|
|
Returns a hashmap (python dictionary) of b -> R(b)
|
||
|
|
for all b such that: min < b < max
|
||
|
|
'''
|
||
|
|
def precompute_R(min: int,
|
||
|
|
max: int) -> dict[int, int]:
|
||
|
|
b = min
|
||
|
|
R_table = {}
|
||
|
|
while b <= max:
|
||
|
|
R_table[b] = Rb(b)
|
||
|
|
b += 1
|
||
|
|
return R_table
|
||
|
|
|
||
|
|
|
||
|
|
def hashfn(x: bytes, R_table: dict[int, int]) -> int:
|
||
|
|
h = -2
|
||
|
|
for i in range(len((x))):
|
||
|
|
b = x[i]
|
||
|
|
h = h**2 * (b+1) + ((K * (i+1)) ^ R_table[b])
|
||
|
|
h %= M
|
||
|
|
return h % M
|
||
|
|
|
||
|
|
def bcrypt(x: bytes) -> int:
|
||
|
|
h = 18446744073709551614
|
||
|
|
|
||
|
|
for (i, b) in enumerate(x):
|
||
|
|
h *= h * (b + 1)
|
||
|
|
k = 59275109328752 * (i + 1)
|
||
|
|
for j in range(8):
|
||
|
|
k ^= b << (j * j)
|
||
|
|
h += k
|
||
|
|
h %= (2 ** 64)
|
||
|
|
|
||
|
|
return h
|
||
|
|
|
||
|
|
def debug_hashes_eq(x: bytes, R_table: dict[int, int]) -> bool:
|
||
|
|
return hashfn(x, R_table) == bcrypt(x)
|
||
|
|
|
||
|
|
def debug_test_random_hashes(trials: int,
|
||
|
|
max_bytes: int = 16,
|
||
|
|
quiet: bool = False) -> bytes | None:
|
||
|
|
R_table = precompute_R(0, 255)
|
||
|
|
for i in range(trials):
|
||
|
|
# generate random bytes
|
||
|
|
num_bytes = randint(0, max_bytes)
|
||
|
|
x = randbytes(num_bytes)
|
||
|
|
|
||
|
|
# test the modified bcrypt with the original
|
||
|
|
hash_test = hashfn(x, R_table)
|
||
|
|
hash_bcrypt = bcrypt(x)
|
||
|
|
if hash_test != hash_bcrypt:
|
||
|
|
if not quiet:
|
||
|
|
print(f'Your hashfn sucks, big mistake bucko!! (iter: {i})')
|
||
|
|
print(hash_test)
|
||
|
|
print(hash_bcrypt)
|
||
|
|
print([str(b) for b in x])
|
||
|
|
return x
|
||
|
|
|
||
|
|
if not quiet:
|
||
|
|
print('Impeccable hashfn holy moly!!')
|
||
|
|
return None
|
||
|
|
|
||
|
|
|
||
|
|
def main() -> None:
|
||
|
|
print(f'gcd(H,K): {gcd(H,K)}')
|
||
|
|
print(f'gcd(H,M): {gcd(H,M)}')
|
||
|
|
print(f'gcd(K,M): {gcd(K,M)}')
|
||
|
|
if debug_test_random_hashes(10000) != None:
|
||
|
|
R_table = precompute_R(0, 255)
|
||
|
|
x = bytes(input('x: '), 'utf-8')
|
||
|
|
hash_test = hashfn(x, R_table)
|
||
|
|
hash_bcrypt = bcrypt(x)
|
||
|
|
print(f'hashfn: {hash_test}')
|
||
|
|
print(f'bcrypt: {hash_bcrypt}')
|
||
|
|
|
||
|
|
# a = bytes(input("A: "), 'utf-8')
|
||
|
|
# b = bytes(input("B: "), 'utf-8')
|
||
|
|
|
||
|
|
# if a != b and hashfn(a) == hashfn(b):
|
||
|
|
# print('*** YOU WIN ***')
|
||
|
|
# elif a == b:
|
||
|
|
# print('Idiot those are the same')
|
||
|
|
# else:
|
||
|
|
# print("Trivially false!")
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == '__main__':
|
||
|
|
try:
|
||
|
|
main()
|
||
|
|
except KeyboardInterrupt:
|
||
|
|
print('\n[!] Received SIGINT')
|
||
|
|
except EOFError:
|
||
|
|
print('\n[!] Reached EOF')
|