Python code to generate private ECDSA key

Would this Python code generate a valid ECDSA private key?

import random

def r(a, b):
sys_ran = random.SystemRandom()
return sys_ran.randint(a, b)

def create_private_key():
hex_chars = '0123456789ABCDEF'
ran_hex = '';

for i in range(64):
ran_hex += hex_chars[r(0, 15)]

max_hex = 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141'

if int(ran_hex, 16) <= int(max_hex, 16):
return ran_hex
else:
return create_private_key()

private_key = create_private_key()
print('Private key: ' + private_key)

As far as I can tell from the Bitcoin wiki, an ECDSA private key is any 64 character hexadecimal (or the corresponding decimal) number between 0x1 and 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141. It doesn't mention anything about any special algorithms required for the private key to be valid.

Yes, it will generate a random ECDSA private key in hexadecimal ASCII form. You don't really need to specifically check whether the key is greater than the maximum -- pretty much every implementation that will take an ECDSA key in hexadecimal ASCII knows how to handle a key above the maximum sanely. (By subtracting the max value from the key and then using that.)

This is not entirely responsive to your question, but in furtherance of David Schwartz's response (which was, in summary, "yes"), I don't think you need to recreate an instance SystemRandom for each hex character you generate. From https://docs.python.org/2/library/random.html#random.SystemRandom:

[SystemRandom] uses the os.urandom() function for generating random numbers from sources provided by the operating system. Not available on all systems. Does not rely on software state and sequences are not reproducible. Accordingly, the seed() and jumpahead() methods have no effect and are ignored. The getstate() and setstate() methods raise NotImplementedError if called.

I think you can call SystemRandom.randint on your bounds directly (with a pretty big speed boost):

from random import SystemRandom
from binascii import hexlify
from struct import Struct

SYS_RAN = SystemRandom()
PACKER = Struct('>QQQQ')
MIN_VAL = 0x1L
MAX_VAL = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141

def mkprivkey():
key = SYS_RAN.randint(MIN_VAL, MAX_VAL)
key0 = key >> 192
key1 = (key >> 128) & 0xffffffffffffffff
key2 = (key >> 64) & 0xffffffffffffffff
key3 = key & 0xffffffffffffffff

return hexlify(PACKER.pack(key0, key1, key2, key3))

In my testing, the above is about an order of magnitude faster, even after normalizing your creation of SystemRandom instances and removing your test to see if you've exceeded the max value (per David Schwartz's suggestion):

% time python ./test_ecdsaprivkey.py
mkprivkey:          0.016 ms avg
create_private_key: 0.168 ms avg
python ./test_ecdsaprivkey.py  9.99s user 11.00s system 86% cpu 24.388 total

Of course, this probably doesn't matter unless you're creating tens of thousands of keys.

import os import binascii private_key = binascii.hexlify(os.urandom(32)).decode() print("private key = " + private_key)

• Welcome to Bitcoin.SE! Whilst this may theoretically answer the question, it would be preferable to include some explanation of your code too so that people can understand how it works and what it does Jan 16 '18 at 9:09