Answering the main headline question about 256-bit private keys, and header:
"For a given private key generated by MyEtherWallet, I would like to
see I have the tools to independently arrive at similar results."
Firstly, it's important to check the private key size (whether generated randomly or deterministically) to make sure it is valid in terms of its use within curve secp256k1 curve (beyond the length in bits of the key), before generating the public key and address (although many applications such as the one below will check for you).
Note: This applies to Bitcoin as well, not just ethereum, as they use the same curves, despite the address formatting being different due to the different steps and different hashing algorithms and encodings used (and although the same private key can be used across both, that is a different discussion).
While the curve itself is equal to the finite field p equal to: ((((((((2**256)-2**32)-2**9)-2**8)-2**7)-2**6)-2**4)-1) and which in hexadecimal is: '0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f' and 256 binary bits long, the private key cannot be larger than the order n which is slighlty smaller even though it is also 256-bits: '0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141'
That is, the private key cannot be larger than n as per the secp256k1 curve parameters.
After making that check to be sure the key is valid, the next steps would be to use something like the ECDSA library along with eth-keys library in Python.
Here below is an example such program in Python that accepts a private key or can generate keys randomly (see comment in code after # for private_key_hex=hex(int(bin(secrets.randbits(256)),base=2))):
import secrets
import math
import sha3
import ecdsa
from ecdsa import SigningKey, SECP256k1
from eth_keys import keys
private_key_hex=hex(int(input('paste a 0x-padded 64 character hex string, total 66 with 0x'),base=16))
scep256k1_curvelimit= int(0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141) #Curve limit is
if int(private_key_hex,base=16) > scep256k1_curvelimit:
print('private key is out of the range of the curve and invalid, do not use!')
else:
print('private key is within range of curve')
#private_key_hex=hex(int(bin(secrets.randbits(256)),base=2)) Uncomment this to use RANDOM
private_key_hex_nopad=private_key_hex[2:]
private_key=bytearray.fromhex(private_key_hex_nopad)
def address_formatted(to_hash_str):
keccak = sha3.keccak_256()
out = ''
str_hash = to_hash_str.lower().replace('0x', '')
keccak.update(str_hash.encode('ascii'))
create_hash_digit = keccak.hexdigest()
for i, c in enumerate(str_hash):
if int(create_hash_digit[i], 16) >= 8:
out += c.upper()
else:
out += c
return '0x' + out
keccak = sha3.keccak_256()
f=private_key
private_key = ecdsa.SigningKey.from_string(f, curve=ecdsa.SECP256k1)
public_key = private_key.get_verifying_key().to_string()
keccak.update(public_key)
print(public_key)
address = keccak.hexdigest()[24:]
address_full = keccak.hexdigest()
print("Private key:", private_key.to_string().hex())
print("Public key: ", public_key.hex())
print("Ethereum Address, based on last 40 hex of Keccak Hash digest: ", address_formatted(address))
print('Full Hash Digest (address is last 40 characters): ',address_full,)
Note: the following code snippet from the above program is not necessary and I just added there for informational purposes, as the depended libraries have inherent checks to tell whether the private key (secret exponent) is less than n :
scep256k1_curvelimit= int(0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141) #Curve limit is
if int(private_key_hex,base=16) > scep256k1_curvelimit:
print('private key is out of the range of the curve and invalid, do not use!')
else:
print('private key is within range of curve')
The output of the above program using the cryptographically-secure randomly-generated 256-bit key would look something like this (don't use these values on main net):
b'\xa2%\xbfV_\xf4\xea\x03\x9b\xcc\xba>&En\x91\x0c\xd7NF\x16\xd6~\xe0\xa1f\xe2m\xa6\xe5\xe5Z\x08\xd0\xfa\x16Y\xb4\xb5G\xbaq9\xcaS\x1fb\x90{\x9c.r\xb8\x07\x12\xf1\xc8\x1e\xceC\xc3?K\x8b'
Private key: c2c72dfbff11dfb4e9d5b0a20c620c58b15bb7552753601f043db91331b0db15
Public key: a225bf565ff4ea039bccba3e26456e910cd74e4616d67ee0a166e26da6e5e55a08d0fa1659b4b547ba7139ca531f62907b9c2e72b80712f1c81ece43c33f4b8b
Ethereum Address, based on last 40 hex of Keccak Hash digest: 0x6eA27154616a29708dce7650b475Dd6b82eBa6a3
Full Hash Digest (address is last 40 characters): f616607efea8e1a5c2f0f8576ea27154616a29708dce7650b475dd6b82eba6a3
Note: Keccak can also be accessed as part of the Hashlib library or installed from the pysha3 library, depending on the Python version installed.
To calculate a public address using bx's secp256k1 capabilities is simply:
% echo fc8fba997174132184998ab82b28e441e80c73236ccaf8b6a1efadc33febecfc | bx ec-to-public -u04cf90dc2b34937fff7cf1eb4b260f1e5610231134b864761e508505938bbef8fc00aeb265797336b74146e018da7b78070f1f1072540a2c3fe83637ca5d605b3c – skaht – 2015-12-30T03:38:44.817Issue I'm having is with Keccak sha3-256. Dropping the 04 from the address above into a sha3-256 and taking the lower 20 bytes to the right isn't working. – skaht – 2015-12-30T03:48:12.353
% ./keccak -x -256 cf90dc2b34937fff7cf1eb4b260f1e5610231134b864761e508505938bbef8fc00aeb265797336b74146e018da7b78070f1f1072540a2c3fe83637ca5d605b3cb992c6ced76bf40cfe875feb99d0dfbbb6eb831dc0605a82d084e5d930bc6631 – skaht – 2015-12-30T03:52:12.413How is it guaranteed that addresses are unique within the network then? What if I happen to have generated the same private key as someone else, then I will have the same address? Or, a more likely scenario, what if my private key is different to someone else, but it maps to the same address? – Graeme Pyle – 2016-05-26T07:14:38.013
Q1) There is no guarantee that two different private keys can't have the same public ETH public address, just very improbable. Q2) If there is a collision between the private keys, s/he that spends first gets to reap booty at the loss of another. More likely to loose your funds at a bank for whatever reason... – skaht – 2016-06-24T00:27:04.220