Skip to content

Instantly share code, notes, and snippets.

@sphinxid
Last active October 13, 2024 06:55
Show Gist options
  • Save sphinxid/610be4302400a3c8dda95421ae0b256c to your computer and use it in GitHub Desktop.
Save sphinxid/610be4302400a3c8dda95421ae0b256c to your computer and use it in GitHub Desktop.
This code simulates a client-server interaction using a Proof-of-Work (PoW) system. In such systems, the client must solve a computational challenge set by the server in order to have its request processed. This particular code makes use of SHA3-256 hashing and requires the hash of a unique challenge and a nonce to have a specific number of lead…
import hashlib
import hmac
import time
import secrets
import random
# Secret Key for HMAC (In a real-world scenario, this should be stored securely)
SECRET_KEY = b"SayaOrangPalingGantengSedunia" # Change this in production
# Difficulty (number of leading zeroes required in the hash)
DIFFICULTY = 5
# Maximum time difference (in seconds)
TIME_DIFF = 300
# Nonce Range
NONCE_RANGE = 10**10
def generate_challenge():
return hashlib.sha3_256(str(secrets.randbits(64)).encode()).hexdigest()
def server_set_challenge():
challenge = generate_challenge()
unique_str = secrets.token_hex(16)
timestamp = int(time.time())
challenge_with_unique_str = challenge + unique_str
digest = hmac.new(SECRET_KEY, f"{challenge_with_unique_str}{timestamp}".encode(), hashlib.sha3_256).hexdigest()
print(f"Server: The challenge is '{challenge}', find a nonce such that the SHA3-256 hash of the challenge + unique string + nonce has at least {DIFFICULTY} leading zeroes.")
return challenge_with_unique_str, timestamp, digest
def client_solve_challenge(challenge, server_timestamp):
print("Client: Solving challenge...")
start_time = time.time()
nonce = random.randint(0, NONCE_RANGE)
while True:
data = f"{challenge}{server_timestamp}{nonce}"
hash_result = hashlib.sha3_256(data.encode()).hexdigest()
if hash_result.startswith("0" * DIFFICULTY):
end_time = time.time()
print(f"Hash result: {hash_result}")
print(f"Client timestamp: {start_time}")
print(f"Server timestamp: {server_timestamp}")
print(f"Client: Challenge solved in {end_time - start_time:.2f} seconds, nonce: {nonce}")
return nonce, int(start_time)
nonce = (nonce + 1) % NONCE_RANGE
def server_verify_solution(challenge, nonce, client_timestamp, server_timestamp, original_digest):
current_timestamp = int(time.time())
# Verify the original challenge hasn't been tampered with
calculated_digest = hmac.new(SECRET_KEY, f"{challenge}{server_timestamp}".encode(), hashlib.sha3_256).hexdigest()
if calculated_digest != original_digest:
print("Server: Challenge has been tampered with.")
return False
# Check if the solution is within the time limit
if current_timestamp - client_timestamp > TIME_DIFF:
print("Server: Solution is too old, request rejected.")
return False
# Verify the solution
data = f"{challenge}{server_timestamp}{nonce}"
hash_result = hashlib.sha3_256(data.encode()).hexdigest()
if hash_result.startswith("0" * DIFFICULTY):
print("Server: Solution is correct, processing request...")
time.sleep(1) # Simulate request processing
print("Server: Request processed")
return True
else:
print("Server: Incorrect solution")
return False
def simulate_api_request():
challenge, server_timestamp, digest = server_set_challenge()
nonce, client_timestamp = client_solve_challenge(challenge, server_timestamp)
server_verify_solution(challenge, nonce, client_timestamp, server_timestamp, digest)
def main():
simulate_api_request()
if __name__ == "__main__":
main()
@sphinxid
Copy link
Author

sphinxid commented Jun 6, 2023

$ python3.10 pow04.py
Server: The challenge is '45834afa64a3eb05a15e01c11feeee05f6dc1db3bae17d7dc15eb55b947de79e', you need to find a nonce such that the SHA3-256 hash of the challenge + unique string, and nonce together has at least 5 leading zeroes.
Client: Solving challenge...
hash result -> 000005faf2176f73d9ff080893587183ef6cf6ed1ef307f930d547dcf5221dc8
client timestamp -> 1686118872.015199
server timestamp -> 1686118872
Client: Challenge solved in 1.4372360706329346 seconds, the nonce is 6410631986
Server: Solution is correct, processing request...
Server: Request processed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment