Advertisement
k98kurz

edpow.py

Jan 11th, 2022
1,186
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.48 KB | None | 0 0
  1. """EdPoW: proof-of-work using 32 byte seeds to generate Ed25519 key pairs where
  2.    the public key matches some kind of difficulty metric.
  3. """
  4.  
  5. from nacl.signing import SigningKey
  6. from secrets import token_bytes
  7. from sys import argv
  8. from typing import Callable
  9. import difficulty
  10.  
  11.  
  12. def edpow(target: int, diff_calc_func: Callable[[bytes], int]) -> tuple[int, int, bytes, bytes]:
  13.     """Find an Ed25519 keypair with a public key with a number of preceding null
  14.        bits equal to the target & measured by the supplied difficulty function.
  15.    """
  16.     # set up some variables
  17.     target = int(target)
  18.     count = 0
  19.     measured_difficulty = 0
  20.     seed = token_bytes(32)
  21.  
  22.     # generate keys until public key of >=specified difficulty found
  23.     while measured_difficulty < target:
  24.         sk = SigningKey(seed)
  25.         measured_difficulty = diff_calc_func(bytes(sk.verify_key))
  26.         count += 1
  27.         new_seed = int.from_bytes(seed, 'little') - 1
  28.         seed = new_seed.to_bytes(32, 'little') if new_seed > 0 else token_bytes(32)
  29.  
  30.     return (count, measured_difficulty, seed, bytes(sk.verify_key))
  31.  
  32. def edpow_bits(target: str):
  33.     """Runs edpow(target, difficulty.calculate)."""
  34.     return edpow(int(target), difficulty.calculate)
  35.  
  36. def edpow_tries(target: str):
  37.     """Runs edpow(target, difficulty.calculate_linear)."""
  38.     return edpow(int(target), difficulty.calculate_linear)
  39.  
  40. def edpow_query(target: bytes):
  41.     """Find an Ed25519 keypair with a public key that contains the target bytes."""
  42.     # set up some variables
  43.     estimated_difficulty = difficulty.calculate_query_bytes(target, 32)
  44.     count = 1
  45.     seed = token_bytes(32)
  46.     sk = SigningKey(seed)
  47.  
  48.     # generate keys until public key contains target
  49.     while target not in bytes(sk.verify_key):
  50.         count += 1
  51.         new_seed = int.from_bytes(seed, 'little') - 1
  52.         seed = new_seed.to_bytes(32, 'little') if new_seed > 0 else token_bytes(32)
  53.         sk = SigningKey(seed)
  54.  
  55.     return (count, estimated_difficulty, seed, bytes(sk.verify_key))
  56.  
  57.  
  58. def license() -> str:
  59.     """ISC License
  60.  
  61.        Copyleft (c) 2022, k98kurz
  62.  
  63.        Permission to use, copy, modify, and/or distribute this software for any
  64.        purpose with or without fee is hereby granted, provided that the above
  65.        copyleft notice and this permission notice appear in all copies.
  66.  
  67.        THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  68.        WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  69.        MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  70.        ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  71.        WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  72.        ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  73.        OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  74.    """
  75.     return license.__doc__
  76.  
  77.  
  78. def usage(name):
  79.     print(f'usage: {name} [mode] [target] [-h]')
  80.     print('\tmode\tb for preceding bits')
  81.     print('\t\tt for number of tries')
  82.     print('\t\tq for specific query bytestring')
  83.     print('\t\tqc for calculating difficulty for a query bytestring')
  84.     print('\ttarget\tinteger difficulty target')
  85.     print('\t-h\tparse target as hexadecimal')
  86.  
  87. def main(args):
  88.     """Command line interface."""
  89.     # print usage if used incorrectly
  90.     if len(args) < 3 or args[1] not in ('b', 't', 'q', 'qc'):
  91.         usage(args[0])
  92.         return
  93.  
  94.     mode = args[1]
  95.  
  96.     # parse target as hexadecimal if necessary
  97.     if len(args) == 4 and args[3] in ('-h', '--hex', 'h', 'hex'):
  98.         target = bytes.fromhex(args[2])
  99.         if mode in ('b', 't'):
  100.             target = int.from_bytes(target, 'little')
  101.     else:
  102.         target = args[2] if mode in ('b', 't') else bytes(args[2], 'utf-8')
  103.  
  104.     # switch on mode
  105.     if mode == 'b':
  106.         result = edpow_bits(target)
  107.         print(f'{result[0]} tries, {result[1]} difficulty, seed={result[2].hex()}, pk={result[3].hex()}')
  108.     elif mode == 't':
  109.         result = edpow_tries(target)
  110.         print(f'{result[0]} tries, {result[1]} difficulty, seed={result[2].hex()}, pk={result[3].hex()}')
  111.     elif mode == 'q':
  112.         result = edpow_query(target)
  113.         print(f'{result[0]} tries, {result[1]} difficulty, seed={result[2].hex()}, pk={result[3].hex()}')
  114.     elif mode == 'qc':
  115.         print(f'{difficulty.calculate_query_bytes(target, 32)} tries')
  116.  
  117.  
  118. if __name__ == '__main__':
  119.     main(argv)
  120.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement