Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from hashlib import new
- from sys import argv
- '''
- Copyleft (c) 2021 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
- copyleft 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.
- '''
- # returns the calculated difficulty
- def calculate(hash: bytes, bigendian: bool = True) -> int:
- # prepare variables
- number = int.from_bytes(hash, byteorder = 'big' if bigendian else 'little')
- length = len(hash)
- trailing_bits = 0
- # shift off bits until a null result is achieved
- while number != 0 and trailing_bits < length * 8:
- number = number >> 1
- trailing_bits += 1
- # difficulty achieved is the preceeding null bits
- return length * 8 - trailing_bits
- # checks if a hash has the correct difficulty (preceeding null bits)
- def check(diff: int, hash: bytes, bigendian: bool = True) -> bool:
- # prepare variables
- number = int.from_bytes(hash, byteorder='big' if bigendian else 'little')
- length = len(hash)
- # raise exception if difficulty is impossible to achieve
- if diff > length * 8:
- raise Exception('Difficulty cannot exceed bit length of input')
- # shift off all but {diff} preceding bits
- preceding_bits = number >> (length * 8 - diff)
- # it meets the difficulty if preceding bits are 0
- return preceding_bits == 0
- # cli
- def main(args):
- op = args[0].split(':')
- mode = args[1].split(':')
- input = args[2]
- bigendian = True if len(args) < 4 else bool(args[3])
- if len(op) == 1:
- # default op, e.g. calculate
- if len(mode) == 1:
- # default mode, e.g. no hashing
- input = bytearray.fromhex(input) if mode[0] == 'hex' else bytes(input, 'utf-8')
- print(calculate(input, bigendian))
- else:
- # hashing mode
- input = new(mode[1], bytes(input, 'utf-8')).digest(len(input)) if 'shake' in mode[1] else new(mode[1], bytes(input, 'utf-8')).digest()
- print(calculate(input, bigendian))
- else:
- # difficulty checking op
- if len(mode) == 1:
- # default mode, e.g. no hashing
- input = bytearray.fromhex(input) if mode[0] == 'hex' else bytes(input, 'utf-8')
- print('pass' if check(int(op[1]), input, bigendian) else 'fail')
- else:
- # hashing mode
- input = new(mode[1], bytes(input, 'utf-8')).digest(len(input)) if 'shake' in mode[1] else new(mode[1], bytes(input, 'utf-8')).digest()
- print('pass' if check(int(op[1]), input, bigendian) else 'fail')
- # cli
- if __name__ == '__main__':
- if len(argv) < 4:
- print('calculate difficulty of a given hash or check if it reaches a threshold')
- print('usage: ' + argv[0] + ' [check:{number}|calc] [hash:{hashlib_algo}|hex|str] [utf-8 string] [bigendian=True]')
- exit(1)
- main(argv[1:])
Add Comment
Please, Sign In to add comment