k98kurz icon

difficulty.py_old

k98kurz | PRO | 01/11/22 08:57:06 PM UTC (Edited) | 0 ⭐ | 1200 👁️ | Never ⏰ | []
Python |

3.45 KB

|

None

|

0 👍

/

0 👎

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:])
 

Comments