Ethereum private key to public
A common API for Ethereum key operations with pluggable backends.
This library and repository was previously located at https://github.com/pipermerriam/ethereum-keys. It was transferred to the Ethereum foundation github in November 2017 and renamed to eth-keys . The PyPi package was also renamed from ethereum-keys to eth-keys .
Running the tests
You can run the tests with:
Or you can install tox to run the full test suite.
Pandoc is required for transforming the markdown README to the proper format to render correctly on pypi.
For Debian-like systems:
To release a new version:
How to bumpversion
The version format for this repo is
To issue the next version in line, specify which part to bump, like make release bump=minor or make release bump=devnum .
If you are in a beta version, make release bump=stage will switch to a stable.
To issue an unstable version when the current version is stable, specify the new version explicitly, like make release bump=»—new-version 2.0.0-alpha.1 devnum»
The KeyAPI object is the primary API for interacting with the eth-keys libary. The object takes a single optional argument in its constructor which designates what backend will be used for eliptical curve cryptography operations. The built-in backends are:
- eth_keys.backends.NativeECCBackend : A pure python implementation of the ECC operations.
- eth_keys.backends.CoinCurveECCBackend : Uses the coincurve library for ECC operations.
By default, eth-keys will try to use the CoinCurveECCBackend , falling back to the NativeECCBackend if the coincurve library is not available.
Note: The coincurve library is not automatically installed with eth-keys and must be installed separately.
The backend argument can be given in any of the following forms.
- Instance of the backend class
- The backend class
- String with the dot-separated import path for the backend class.
The backend can also be configured using the environment variable ECC_BACKEND_CLASS which should be set to the dot-separated python import path to the desired backend.
KeyAPI.ecdsa_sign(message_hash, private_key) -> Signature
This method returns a signature for the given message_hash , signed by the provided private_key .
- message_hash : must be a byte string of length 32
- private_key : must be an instance of PrivateKey
KeyAPI.ecdsa_verify(message_hash, signature, public_key) -> bool
Returns True or False based on whether the provided signature is a valid signature for the provided message_hash and public_key .
- message_hash : must be a byte string of length 32
- signature : must be an instance of Signature
- public_key : must be an instance of PublicKey
KeyAPI.ecdsa_recover(message_hash, signature) -> PublicKey
Returns the PublicKey instances recovered from the given signature and message_hash .
- message_hash : must be a byte string of length 32
- signature : must be an instance of Signature
Returns the PublicKey instances computed from the given private_key instance.
- private_key : must be an instance of PublicKey
Common APIs for PublicKey , PrivateKey and Signature
There is a common API for the following objects.
Each of these objects has all of the following APIs.
- obj.to_bytes() : Returns the object in it’s canonical bytes serialization.
- obj.to_hex() : Returns a text string of the hex encoded canonical representation.
The PublicKey class takes a single argument which must be a bytes string with length 64.
Note that there are two other common formats for public keys: 65 bytes with a leading \x04 byte and 33 bytes starting with either \x02 or \x03 . To use the former with the PublicKey object, remove the first byte. For the latter, refer to PublicKey.from_compressed_bytes .
The following methods are available:
This classmethod returns a new PublicKey instance computed from its compressed representation.
- compressed_bytes must be a byte string of length 33 starting with \x02 or \x03 .
This classmethod returns a new PublicKey instance computed from the given private_key .
- private_key may either be a byte string of length 32 or an instance of the KeyAPI.PrivateKey class.
PublicKey.recover_from_msg(message, signature) -> PublicKey
This classmethod returns a new PublicKey instance computed from the provided message and signature .
- message must be a byte string
- signature must be an instance of KeyAPI.Signature
PublicKey.recover_from_msg_hash(message_hash, signature) -> PublicKey
Same as PublicKey.recover_from_msg except that message_hash should be the Keccak hash of the message .
PublicKey.verify_msg(message, signature) -> bool
This method returns True or False based on whether the signature is a valid for the given message.
PublicKey.verify_msg_hash(message_hash, signature) -> bool
Same as PublicKey.verify_msg except that message_hash should be the Keccak hash of the message .
Returns the compressed representation of this public key.
Returns the hex encoded ethereum address for this public key.
Returns the ERC55 checksum formatted ethereum address for this public key.
Returns the 20-byte representation of the ethereum address for this public key.
The PrivateKey class takes a single argument which must be a bytes string with length 32.
The following methods and properties are available
This property holds the PublicKey instance coresponding to this private key.
This method returns a signature for the given message in the form of a Signature instance
- message must be a byte string.
Same as PrivateKey.sign except that message_hash should be the Keccak hash of the message .
The Signature class can be instantiated in one of two ways.
- signature_bytes : a bytes string with length 65.
- vrs : a 3-tuple composed of the integers v , r , and s .
Note: If using the signature_bytes to instantiate, the byte string should be encoded as r_bytes | s_bytes | v_bytes where | represents concatenation. r_bytes and s_bytes should be 32 bytes in length. v_bytes should be a single byte \x00 or \x01 .
Signatures are expected to use 1 or 0 for their v value.
The following methods and properties are available
This property returns the v value from the signature as an integer.
This property returns the r value from the signature as an integer.
This property returns the s value from the signature as an integer.
This property returns a 3-tuple of (v, r, s) .
Signature.verify_msg(message, public_key) -> bool
This method returns True or False based on whether the signature is a valid for the given public key.
- message : must be a byte string.
- public_key : must be an instance of PublicKey
Signature.verify_msg_hash(message_hash, public_key) -> bool
Same as Signature.verify_msg except that message_hash should be the Keccak hash of the message .
This method returns a PublicKey instance recovered from the signature.
- message : must be a byte string.
Same as Signature.recover_public_key_from_msg except that message_hash should be the Keccak hash of the message .
This error is raised during instantaition of any of the PublicKey , PrivateKey or Signature classes if their constructor parameters are invalid.
This error is raised from any of the recover or verify methods involving signatures if the signature is invalid.
Источник
Location of public and private keys of Ethereum account
I want to know the details about key generation and handling in Parity. The questions listed are all related, so I put them all in this one question post.
When a new Ethereum account is created on Parity, a new file is created under . /ethcore/ /keys/ . As an example, the contents of such a file are:
Looks like the KDF is PBKDF2, i.e. password-based KDF. I guess the account password is used to derive the keys and the parameters for that are given in «kdfparams» .
So, I am looking for answers to the following questions:
- Is the private key derived using this KDF and the given param values, on-demand whenever the password is supplied?
- What is the public key, or how is it generated? The password should not be needed for that.
- What is the plain text that «ciphertext» is the encryption of?
- This file is generated and saved on the Parity node. Doesn’t that mean that the private key is not completely and solely in the hands of the account owner?
Thanks for throwing some light on this issue.
1 Answer 1
Some of the links in the comments helped me get the answers to my questions. I have collected all that information combined with my own (recently acquired) knowledge of cryptography from the Coursera Cryptography-I class (for the answer to question number 3).
A1. The private key is never (or should never be) saved unencrypted on disk. It is generated from the info in the keystore file when the user enters the password.
A2. The public key can be generated from the private key. However, it is needed by other parties (that do not have the private key) to verify signatures by this account. These parties would derive it from a signature, as explained here: Get public key of any ethereum account Then, the signer’s address is the last 20 bytes of the Keccak-256 hash of the public key. Presumably, that should match the from: address of the transaction.
A3. Here is a (somewhat long) answer about the structure and meaning of the private key’s JSON representation:
I got a lot of this information from the wiki page: https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition and added some of my own to make it more comprehensive.
All the information to decrypt the private key is in the crypto element. The cipher element identifies the symmetric encryption scheme used to encrypt the private key. In the given example, the scheme is aes-128-ctr , the Advanced Encryption Standard ( aes ) block cipher with a key length of 128 bits in the counter ( ctr ) mode of operation. Aside: The other mode of operation is cipher block chaining (CBC). cipherparams contains the values of any parameters used in the encryption. For AES-128-CTR, there is only one parameter, iv (Initialization Vector). ciphertext is the encrypted private key.
To decrypt the private key’s ciphertext , we need the above values. We also need the symmetric encryption key, which was used to encrypt the private key. The encryption key is not shown in plain text either. It needs to be derived using the specified key derivation function ( kdf ) using the values of the parameters that the specified KDF needs ( kdfparams ). The KDF in the given example is pbkdf2 — a password-based KDF. The parameters for pbkdf2 are the password (to be entered by the user), a pseudo-random hashing function ( prf ) (in example, it is HMAC-SHA256 hmac-sha256 ), a salt value ( salt ), an iteration count ( c ) and the derived key length ( dklen ) in bytes. The key is derived by taking the concatenation of the password and salt values, and applying the hashing function c times. This is done because passwords selected by humans do not have sufficient entropy. To defend against that, a random salt value is used and also a slow hash function. (The number of iterations is to make the hash function slower. It does not make the key derivation any more secure (as some believe). It only makes it take longer so as to make brute-force attacks more difficult.)
After deriving the encryption key, it is verified using the MAC value ( mac ). The second block of 128 bits (16 bytes) is concatenated with the ciphertext value. The Keccak-256 hash of the resulting byte array should be equal to the mac value.
If the encryption key passes verification, then it is used to decrypt the ciphertext , using the decryption function of the specified cipher with the parameter values given in cipherparams . The result of this decryption is the plain text private key.
A4. I realized later that a new account should be created only on a node controlled by oneself. That is the reason that the personal API is enabled by default on IPC, but not on RPC, to prevent a new account creation request being accepted by a remote node.
Источник
How to create an Ethereum wallet address from a private key
In the first article of this series, we generated a bitcoin private key: 60cf347dbc59d31c1358c8e5cf5e45b822ab85b79cb32a9f3d98184779a9efc2 .
Here, we’ll use that key to get the public address and then the Ethereum wallet address of that private key.
Creating the Bitcoin wallet address from the private key is a bit complicated. Here, the process will be much simpler. We need to apply one hash function to get the public key and another one to get the address.
So let’s get started.
Public key
This part is almost identical to what we discussed in the Bitcoin article, so if you read that one, you can skip it (unless you need a refresher).
The first thing we need to go is to apply the ECDSA, or Elliptic Curve Digital Signature Algorithm, to our private key. An elliptic curve is a curve defined by the equation y² = x³ + ax + b with chosen a and b . There is a whole family of such curves that are widely known and used. Bitcoin uses the secp256k1 curve. If you want to learn more about Elliptic Curve Cryptography, I’ll refer you to this article.
Ethereum uses the same elliptic curve, secp256k1, so the process to get the public key is identical in both cryptocurrencies.
By applying the ECDSA to the private key, we get a 64-byte integer, which is two 32-byte integers that represent X and Y of the point on the elliptic curve, concatenated together.
For our example, we got 1e7bcc70c72770dbb72fea022e8a6d07f814d2ebe4de9ae3f7af75bf706902a7b73ff919898c836396a6b0c96812c3213b99372050853bd1678da0ead14487d7 .
In Python, it would look like this:
Note: as you can see from the code above, I used a method from the ecdsa module and I decoded the private key using codecs . This is relevant more to the Python and less to the algorithm itself, but I will explain what are we doing here to remove possible confusion.
In Python, there are at least two classes that can keep the private and public keys: “str” and “bytes”. The first is a string and the second is a byte array. Cryptographic methods in Python work with a “bytes” class, taking it as input and returning it as the result.
Now, there’s a little catch: a string, say, 4f3c does not equal the byte array 4f3c . Rather, it equals the byte array with two elements, O . And that’s what the codecs.decode method does: it converts a string into a byte array. This will be the same for all cryptographic manipulations that we’ll do in this article.
Wallet address
Once we’ve gotten the public key, we can calculate the address. Now, unlike Bitcoin, Ethereum has the same addresses on both the main and all test networks. Users specify the network that they want to use later in the process when they make and sign a transaction.
To make an address from the public key, all we need to do is to apply Keccak-256 to the key and then take the last 20 bytes of the result. And that’s it. No other hash functions, no Base58 or any other conversion. The only thing you need is to add ‘0x’ at the start of the address.
Here’s the Python code:
Checksum
Now, as you may remember, Bitcoin creates the checksum by hashing the public key and taking the first 4 bytes of the result. This is true for all Bitcoin addresses, so you can’t get the valid address without adding the checksum bytes.
In Ethereum, that’s not how things work. Initially, there were no checksum mechanisms to validate the integrity of the key. However, in 2016, Vitalik Buterin introduced a checksum mechanism, which has since been adopted by wallets and exchanges.
Adding a checksum to the Ethereum wallet address makes it case-sensitive.
First, you need to get the Keccak-256 hash of the address. Note that this address should be passed to the hash function without the 0x part.
Second, you iterate over the characters of the initial address. If the ith byte of the hash is greater than or equal to 8, you convert the ith address’s character to uppercase, otherwise you leave it lowercase.
Finally, you add 0x back at the start of the resulting string. The checksum address is the same as the initial one if you ignore the case. But the uppercase letters let anyone check that the address is indeed valid. You can find the algorithm of the checksum validation at the page linked here.
As you’ll read in the proposal, for this checksum scheme,
“on average there will be 15 check bits per address, and the net probability that a randomly generated address if mistyped will accidentally pass a check is 0.0247%.”
And here’s the code to add checksum to the Ethereum address:
Conclusion
As you can see, creating an address for Ethereum is much simpler than for Bitcoin. All we need to do is to apply the ECDSA to public key, then apply Keccak-256, and finally take the last 20 bytes of that hash.
Источник