from hashlib import ( sha256, md5, shake_128, shake_256, sha3_256, sha3_512, blake2b, blake2s ) """New randomized proof-of-work hashing algorithms inspired roughly by XMR's RandomX but much simpler and shoddier. Mirrors: https://pastebin.com/xY3B3K8S https://github.com/k98kurz/tapehash """ def tapehash1(preimage: bytes, code_size: int = 20) -> bytes: """Runs the tapehash 1 algorithm on the preimage and returns a 32-byte hash. Computational complexity is tuneable via the `code_size` parameter. """ if type(preimage) is not bytes: raise TypeError('preimage must be bytes') if type(code_size) is not int: raise TypeError('code_size must be an int between 1 and 65,536') if code_size <= 0 or code_size > 65_536: raise ValueError('code_size must be an int between 1 and 65,536') # generate the code and the tape code = shake_256(preimage).digest(code_size) tape = bytearray(blake2b(preimage).digest()) # run the program for i in range(0, len(code)): opcode = code[i] >> 4 #pointer = ((code[i] << 4) % 256) >> 4 pointer = code[i] & 0b00001111 double_pointer = int.from_bytes(code[i:i+2], 'big') % 2 tape = execute_opcode(opcode, pointer, tape) tape = execute_opcode(opcode, pointer + 16, tape) tape = execute_opcode(opcode, pointer + 32, tape) tape = execute_opcode(opcode, pointer + 48, tape) return sha256(tape).digest() def tapehash2(preimage: bytes, tape_size_multiplier: int = 2) -> bytes: """Runs the tapehash2 algorithm on the preimage and returns a 32-byte hash. Memory complexity can be tuned via the `tape_size_multiplier` parameter. """ if type(preimage) is not bytes: raise TypeError('preimage must be bytes') if type(tape_size_multiplier) is not int: raise TypeError('tape_size_multiplier must be an int between 1 and 65,536') if tape_size_multiplier <= 0 or tape_size_multiplier > 65_536: raise ValueError('tape_size_multiplier must be an int between 1 and 65,536') # generate the code and the tape code = blake2b(preimage).digest() tape = bytearray(shake_256(preimage).digest(tape_size_multiplier * 32)) # run the program for i in range(0, len(code), 2): opcode = code[i] >> 4 #pointer = ((code[i] << 4) % 256) >> 4 pointer = code[i] & 0b00001111 double_pointer = int.from_bytes(code[i:i+2], 'big') % tape_size_multiplier tape = execute_opcode(opcode, pointer + double_pointer * 32, tape) tape = execute_opcode(opcode, pointer + 16 + double_pointer * 32, tape) return sha256(tape).digest() def tapehash3( preimage: bytes, code_size: int = 64, tape_size_multiplier: int = 2 ) -> bytes: """Runs the tapehash3 algorithm on the preimage and returns a 32-byte hash. Computational complexity is tuneable via the `code_size` parameter. Memory complexity is tuneable via the `tape_size_multiplier` parameter. """ if type(preimage) is not bytes: raise TypeError('preimage must be bytes') if type(code_size) is not int: raise TypeError('code_size must be an int between 1 and 65,536') if code_size <= 0 or code_size > 65_536: raise ValueError('code_size must be an int between 1 and 65,536') if type(tape_size_multiplier) is not int: raise TypeError('tape_size_multiplier must be an int between 1 and 65,536') if tape_size_multiplier <= 0 or tape_size_multiplier > 65_536: raise ValueError('tape_size_multiplier must be an int between 1 and 65,536') # generate the code and the tape code = shake_256(preimage).digest(code_size) tape = bytearray(shake_256(preimage).digest(tape_size_multiplier * 32)) # run the program for i in range(0, len(code), 2): opcode = code[i] >> 4 #pointer = ((code[i] << 4) % 256) >> 4 pointer = code[i] & 0b00001111 double_pointer = int.from_bytes(code[i:i+2], 'big') % tape_size_multiplier tape = execute_opcode(opcode, pointer + double_pointer * 32, tape) tape = execute_opcode(opcode, pointer + 16 + double_pointer * 32, tape) return sha256(tape).digest() def rotate_tape(tape: bytearray, pointer: int) -> bytes: """Rotates the tape so that the pointer-indexed byte is first.""" if not isinstance(tape, bytearray): raise TypeError('tape must be bytearray') if not isinstance(pointer, int): raise TypeError('pointer must be int') if len(tape) < 1: raise ValueError('tape must not be empty') if pointer < 0 or pointer >= len(tape): raise ValueError('pointer must be a valid index of tape') new_tape = tape[pointer:] new_tape.extend(tape[:pointer]) return bytes(new_tape) def execute_opcode(opcode: int, pointer: int, tape: bytearray) -> bytearray: """Execute a single opcode.""" if type(opcode) is not int: raise TypeError('opcode must be an int') if type(pointer) is not int: raise TypeError('pointer must be an int') if type(tape) is not bytearray: raise TypeError('tape must be bytearray') if opcode < 0 or opcode > 15: raise ValueError('opcode must be between 0 and 15') if pointer < 0 or pointer >= len(tape): raise ValueError('pointer must be a valid index of tape') operations = { 0: lambda data: data, # no op 1: lambda data: (data + 1) % 256, 2: lambda data: data - 1 if data > 0 else 255, 3: lambda data: data >> 1, 4: lambda data: (data << 1) % 256, 5: lambda data: data ^ 255, 6: lambda data: (data * 2) % 256, 7: lambda data: (data ** 2) % 256, 8: lambda data: (data // 2) % 256, 9: lambda data: ((data << 4) % 256) | (data >> 4), 10: lambda data: sha256(data).digest()[data[0] % 32], 11: lambda data: md5(data).digest()[data[0] % 16], 12: lambda data: shake_128(data).digest(data[0] + 1)[data[0]], 13: lambda data: sha3_256(data).digest()[data[0] % 32], 14: lambda data: sha3_512(data).digest()[data[0] % 64], 15: lambda data: blake2s(data).digest()[data[0] % 32] } if opcode < 10: tape[pointer] = operations[opcode](tape[pointer]) else: tape[pointer] = operations[opcode](rotate_tape(tape, pointer)) return tape def license(): """Copyright (c) 2026 Jonathan Voss (k98kurz) Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """ return license.__doc__