Hashgate - simple PoW/Hashcash-like spam protection algorithm for centralised systems
"""
Hashgate Algorithm.
It's just a preimage puzzle with lookup-table defence.
1. The server generates the key, the code and the hash, where:
hash = SHA256(challenge + key)
The challenge and the key are measured in bytes.
The challenge is preferably 16 bytes.
The key is the "difficulty", which rises exponentially.
2. The server sends the challenge and the hash to the user
3. The user can now calculate the key to access the server
"""
import hashlib
import secrets
import itertools
def sha256(data: bytes) -> bytes:
"""A wrapper function for SHA256"""
return hashlib.sha256(data).digest()
# It doesn't matter how long the "challenge" is.
# And it makes the algorithm secure from look-up tables!
# There shouldn't be any significant computational impact.
# The purpose is to make the algorithm secure from lookup tables.
# 16 bytes (128 bits) would be enough to make it practically unique.
challenge = secrets.token_bytes(16)
# And this thing sets the difficulty:
# I think 3 bytes would be okay, but enough to stop spam.
KEY_LENGTH = 3
key = secrets.token_bytes(KEY_LENGTH)
hashgate = sha256(challenge + key)
# Let's try to brute-force it now xD
print(f"Challenge: {challenge.hex()}")
print(f"Key: {key.hex()}")
print(f"Hash: {hashgate.hex()}")
for guess in itertools.product(range(256), repeat=KEY_LENGTH):
guess_key = bytes(guess)
guess_hash = sha256(challenge + guess_key)
if guess_hash == hashgate:
print(f"Found key: {guess_key.hex()}")
break
"""
Hashgate Algorithm.
It's just a preimage puzzle with lookup-table defence.
1. The server generates the key, the code and the hash, where:
hash = SHA256(challenge + key)
The challenge and the key are measured in bytes.
The challenge is preferably 16 bytes.
The key is the "difficulty", which rises exponentially.
2. The server sends the challenge and the hash to the user
3. The user can now calculate the key to access the server
"""
import hashlib
import secrets
import itertools
def sha256(data: bytes) -> bytes:
"""A wrapper function for SHA256"""
return hashlib.sha256(data).digest()
# It doesn't matter how long the "challenge" is.
# And it makes the algorithm secure from look-up tables!
# There shouldn't be any significant computational impact.
# The purpose is to make the algorithm secure from lookup tables.
# 16 bytes (128 bits) would be enough to make it practically unique.
challenge = secrets.token_bytes(16)
# And this thing sets the difficulty:
# I think 3 bytes would be okay, but enough to stop spam.
KEY_LENGTH = 3
key = secrets.token_bytes(KEY_LENGTH)
hashgate = sha256(challenge + key)
# Let's try to brute-force it now xD
print(f"Challenge: {challenge.hex()}")
print(f"Key: {key.hex()}")
print(f"Hash: {hashgate.hex()}")
for guess in itertools.product(range(256), repeat=KEY_LENGTH):
guess_key = bytes(guess)
guess_hash = sha256(challenge + guess_key)
if guess_hash == hashgate:
print(f"Found key: {guess_key.hex()}")
break
1 Reply
did i just reinvent some wheel? i really wanted to find such algo, but there was none!
anyways it's not complicated
it's more lightweight than PoW, so that makes it more suitable for centralised systems.
Stuff like APIs, email
Also:
1) It is deterministic
2) It is customizable
3) It is very simple