k98kurz icon

edpow.py

k98kurz | PRO | 01/11/22 09:00:08 PM UTC | 0 ⭐ | 1511 👁️ | Never ⏰ | []
Python |

4.48 KB

|

None

|

0 👍

/

0 👎

"""EdPoW: proof-of-work using 32 byte seeds to generate Ed25519 key pairs where
    the public key matches some kind of difficulty metric.
"""
 
from nacl.signing import SigningKey
from secrets import token_bytes
from sys import argv
from typing import Callable
import difficulty
 
 
def edpow(target: int, diff_calc_func: Callable[[bytes], int]) -> tuple[int, int, bytes, bytes]:
    """Find an Ed25519 keypair with a public key with a number of preceding null
        bits equal to the target & measured by the supplied difficulty function.
    """
    # set up some variables
    target = int(target)
    count = 0
    measured_difficulty = 0
    seed = token_bytes(32)
 
    # generate keys until public key of >=specified difficulty found
    while measured_difficulty < target:
        sk = SigningKey(seed)
        measured_difficulty = diff_calc_func(bytes(sk.verify_key))
        count += 1
        new_seed = int.from_bytes(seed, 'little') - 1
        seed = new_seed.to_bytes(32, 'little') if new_seed > 0 else token_bytes(32)
 
    return (count, measured_difficulty, seed, bytes(sk.verify_key))
 
def edpow_bits(target: str):
    """Runs edpow(target, difficulty.calculate)."""
    return edpow(int(target), difficulty.calculate)
 
def edpow_tries(target: str):
    """Runs edpow(target, difficulty.calculate_linear)."""
    return edpow(int(target), difficulty.calculate_linear)
 
def edpow_query(target: bytes):
    """Find an Ed25519 keypair with a public key that contains the target bytes."""
    # set up some variables
    estimated_difficulty = difficulty.calculate_query_bytes(target, 32)
    count = 1
    seed = token_bytes(32)
    sk = SigningKey(seed)
 
    # generate keys until public key contains target
    while target not in bytes(sk.verify_key):
        count += 1
        new_seed = int.from_bytes(seed, 'little') - 1
        seed = new_seed.to_bytes(32, 'little') if new_seed > 0 else token_bytes(32)
        sk = SigningKey(seed)
 
    return (count, estimated_difficulty, seed, bytes(sk.verify_key))
 
 
def license() -> str:
    """ISC License
 
        Copyleft (c) 2022, 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.
    """
    return license.__doc__
 
 
def usage(name):
    print(f'usage: {name} [mode] [target] [-h]')
    print('\tmode\tb for preceding bits')
    print('\t\tt for number of tries')
    print('\t\tq for specific query bytestring')
    print('\t\tqc for calculating difficulty for a query bytestring')
    print('\ttarget\tinteger difficulty target')
    print('\t-h\tparse target as hexadecimal')
 
def main(args):
    """Command line interface."""
    # print usage if used incorrectly
    if len(args) < 3 or args[1] not in ('b', 't', 'q', 'qc'):
        usage(args[0])
        return
 
    mode = args[1]
 
    # parse target as hexadecimal if necessary
    if len(args) == 4 and args[3] in ('-h', '--hex', 'h', 'hex'):
        target = bytes.fromhex(args[2])
        if mode in ('b', 't'):
            target = int.from_bytes(target, 'little')
    else:
        target = args[2] if mode in ('b', 't') else bytes(args[2], 'utf-8')
 
    # switch on mode
    if mode == 'b':
        result = edpow_bits(target)
        print(f'{result[0]} tries, {result[1]} difficulty, seed={result[2].hex()}, pk={result[3].hex()}')
    elif mode == 't':
        result = edpow_tries(target)
        print(f'{result[0]} tries, {result[1]} difficulty, seed={result[2].hex()}, pk={result[3].hex()}')
    elif mode == 'q':
        result = edpow_query(target)
        print(f'{result[0]} tries, {result[1]} difficulty, seed={result[2].hex()}, pk={result[3].hex()}')
    elif mode == 'qc':
        print(f'{difficulty.calculate_query_bytes(target, 32)} tries')
 
 
if __name__ == '__main__':
    main(argv)
 

Comments