Wallets

A BitcoinEvo wallet can refer to either a wallet software program or a wallet file.

Introductions

Wallet programs generate public keys that allow users to receive satoshis, while using the corresponding private keys to spend them. Wallet files, on the other hand, store those private keys and, optionally, other information related to transactions handled by the wallet program.

The following sections address both wallet programs and wallet files separately, and throughout this document, we aim to make it clear whether we’re discussing the wallet programs or the wallet files.

Wallet Programs

The main function of wallet software is to enable the receiving and spending of satoshis — though a particular wallet program doesn’t necessarily need to perform both actions. In fact, two different programs can collaborate, with one generating public keys for receiving satoshis, and another program handling the signing of transactions to spend those satoshis.

Wallet programs must also connect to the peer-to-peer network in order to retrieve blockchain information and broadcast new transactions. However, programs that manage public key distribution or transaction signing don’t always need to directly interact with the peer-to-peer network.

This results in three essential, though separable, components of a wallet system: a program to distribute public keys, a program for signing transactions, and a networked program to communicate with the blockchain. Below, we describe common combinations of these components in detail.

Note: We speak about distributing public keys in a broad sense. In many instances, P2PKH or P2SH hashes are shared instead of the actual public keys, which are only revealed when the outputs they control are spent.

Full-Service Wallets

The most straightforward wallet is a program that handles all three core functions: generating private keys, deriving the associated public keys, managing public key distribution, monitoring for incoming transactions to those public keys, creating and signing transactions to spend those funds, and broadcasting the signed transactions to the network.


Full-Service Wallets


/ As of this writing, nearly all widely-used wallets can function as full-service wallets.

The primary benefit of full-service wallets is their ease of use. A single program handles everything necessary for the user to receive and spend satoshis.

However, the main drawback of full-service wallets is that they store private keys on devices connected to the internet. Compromises of such devices are relatively common, and an active internet connection makes it easy for an attacker to extract private keys from a compromised system.

To mitigate the risk of theft, many wallet programs offer the option to encrypt wallet files that contain private keys. This provides some protection when the private keys aren’t in use, but it doesn’t defend against attacks aimed at capturing the encryption key or reading decrypted keys from the device’s memory.

Signing-Only Wallets

For improved security, private keys can be generated and stored by a separate wallet program running in a more secure environment. These signing-only wallets work alongside a networked wallet, which handles communication with the peer-to-peer network. Signing-only wallet programs often use deterministic key creation (discussed in a later section) to generate a master private key and corresponding master public key, which can, in turn, create multiple derived private and public keys.


Signing-Only Wallets


When first initialized, the signing-only wallet creates a master private key and provides the associated master public key to the networked wallet.

The networked wallet uses the master public key to generate child public keys, helps distribute them if needed, monitors for outputs directed to those public keys, creates unsigned transactions to spend those outputs, and then forwards these unsigned transactions to the signing-only wallet.

Typically, users are given the opportunity to review the unsigned transaction details (particularly the outputs) using the signing-only wallet.

After the optional review, the signing-only wallet derives the necessary child private keys from the master private key and signs the transactions, returning them to the networked wallet.

The networked wallet then broadcasts the signed transactions to the peer-to-peer network.

The following subsections will cover the two most common types of signing-only wallets: offline wallets and hardware wallets.

Offline Wallets

Several full-service wallet programs can also operate as two separate wallets: one instance functioning as a signing-only wallet (commonly called an “offline wallet”) and the other acting as the networked wallet (often referred to as an “online wallet” or “watch-only wallet”).

The offline wallet is named as such because it is designed to run on a device that remains disconnected from any network, significantly reducing potential attack vectors. In this setup, the user is generally responsible for transferring data using external storage devices, such as USB drives. The typical workflow looks like this:

  1. (Offline) Disable all network connections on a device, install the wallet software, and launch the software in offline mode to generate the parent private and public keys. Save the parent public key to a removable storage device.

  2. (Online) On a separate device with internet access, install the wallet software and import the parent public key from the removable media. Distribute public keys as needed to receive payments. When you’re ready to spend satoshis, enter the transaction details and save the unsigned transaction to the removable media.

  3. (Offline) Load the unsigned transaction on the offline wallet, review the output details to ensure the correct amount and address are specified. This step helps prevent any malware on the online device from tricking the user into signing a fraudulent transaction. Once reviewed, sign the transaction and save it back to the removable media.

  4. (Online) Load the signed transaction on the online wallet so it can be broadcasted to the peer-to-peer network.

The key advantage of offline wallets is their potential for significantly enhanced security compared to full-service wallets. As long as the offline wallet remains uncompromised and the user carefully reviews all outgoing transactions, their satoshis are safe — even if the online wallet is compromised.

The main drawback is the inconvenience. For maximum security, users must dedicate a device solely for offline use. The offline device needs to be powered up whenever funds are to be spent, and data must be manually transferred between the online and offline devices.

Hardware Wallets

Hardware wallets are specialized devices designed solely for running a signing-only wallet. Their singular focus on security allows them to avoid many of the risks inherent in general-purpose operating systems, and they can safely communicate with other devices directly, eliminating the need for manual data transfer. The typical workflow looks like this:

  1. (Hardware) Generate the parent private and public keys on the hardware wallet. Connect the hardware wallet to a networked device to provide the parent public key.

  2. (Networked) Distribute public keys as usual to receive payments. When you’re ready to spend satoshis, input the transaction details, connect the hardware wallet, and initiate the spend action. The networked wallet automatically sends the transaction details to the hardware wallet.

  3. (Hardware) Review the transaction details on the hardware wallet’s screen. Some devices may require a passphrase or PIN for confirmation. The hardware wallet then signs the transaction and transfers it back to the networked wallet.

  4. (Networked) The networked wallet receives the signed transaction from the hardware wallet and broadcasts it to the network.

The main advantage of hardware wallets is that they offer a high level of security with less hassle than offline wallets.They eliminate many vulnerabilities present in general-purpose systems and streamline the process by automatically handling data transfer.

However, the main downside of hardware wallets is still the inconvenience. While less cumbersome than offline wallets, users still need to purchase a hardware device and carry it with them whenever they want to make a transaction using the signing-only wallet.

A secondary disadvantage is that, as of this writing, only a few popular wallet programs fully support hardware wallets. However, most wallet developers have announced plans to support at least one model of hardware wallet soon.

Distributing-Only Wallets

Wallet programs that operate in challenging-to-secure environments, such as webservers, can be designed to only distribute public keys (including P2PKH or P2SH addresses) and nothing else. There are two common approaches to designing these minimalist wallets:


Distributing-Only Wallets

  • Pre-populate a database with a series of public keys or addresses, and distribute a pubkey script or address upon request from the database. To prevent key reuse, webservers should track the keys that have been used and ensure they never run out of new public keys. This can be simplified by using parent public keys, as described in the following method.

  • Use a parent public key to generate child public keys. To avoid key reuse, a system is required to ensure that the same public key is not assigned more than once. This could be achieved with a database entry for each key that has been distributed or by using an incrementing key index number.

Neither method adds much overhead, particularly if a database is already being used to associate each incoming payment with a unique public key for payment tracking. Refer to the Payment Processing section for more information.

Wallet Files

At their core, BitcoinEvo wallets are simply collections of private keys. These collections can be stored digitally in a file or even physically on paper.

Private Key Formats

Private keys are the essential elements used to unlock satoshis from a specific address. In BitcoinEvo, a standard private key is a 256-bit number that falls within the following range: 0x01 and 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4140, representing nearly the entire range of 2^256-1 values. This range is determined by the secp256k1 ECDSA encryption standard utilized by BitcoinEvo.

Wallet Import Format (WIF)

To make copying private keys less error-prone, Wallet Import Format (WIF) can be used. WIF applies base58Check encoding to a private key, which greatly reduces the likelihood of mistakes during copying — similar to how BitcoinEvo addresses work.

  1. Start with a private key.br>
  2. Prepend a 0x80 byte to it for mainnet addresses, or 0xef for testnet addresses.
  3. Append a 0x01 byte at the end if the key is for use with compressed public keys (discussed in a later section). If the key is used with uncompressed public keys, no byte is appended.
  4. Perform a SHA-256 hash on the extended key.
  5. Perform another SHA-256 hash on the result of the first hash.
  6. Extract the first four bytes of the second SHA-256 hash; this becomes the checksum.
  7. Append the four checksum bytes from step 6 to the end of the extended key from step 2.
  8. Convert the resulting byte string into a Base58 string using Base58Check encoding.
This process is easily reversible using the Base58 decoding function, followed by removing the padding.

Mini Private Key Format

The mini private key format is a method used to encode a private key in fewer than 30 characters. This allows the key to be stored in compact physical spaces, such as on physical bitcoinevo tokens, and in more damage-resistant QR codes.

  1. Mini keys always start with the letter ‘S’.
  2. To check if a mini private key is properly formatted, a question mark is appended to the key.
  3. Then, a SHA256 hash is calculated. If the first byte of the hash result is `00’, the key is considered well-formatted. This formatting constraint provides a built-in typo-checking mechanism. Users can brute force the process by generating random numbers until a valid, well-formatted mini private key is found.
  4. To derive the full private key from a mini key, a single SHA256 hash of the mini private key is performed. This is a one-way process: it is computationally infeasible to determine the original mini private key from the derived full private key.
Many implementations prevent the use of the character ‘1’ in mini private keys due to its resemblance to the lowercase letter ‘l’.

Public Key Formats

BitcoinEvo’s ECDSA public keys represent a point on a specific Elliptic Curve (EC) defined by the secp256k1 standard. In their traditional, uncompressed format, public keys consist of an identification byte followed by a 32-byte X coordinate and a 32-byte Y coordinate. The simplified illustration below represents a point on the elliptic curve used by BitcoinEvo, defined by the equation y² = x³ + 7, over a field of sequential numbers.


Point On ECDSA Curve

(Secp256k1 actually modulates coordinates using a large prime number, resulting in a field of non-contiguous integers. This makes the curve less visually intuitive, but the underlying principles remain the same.)

A nearly 50% reduction in public key size can be achieved without altering any core functionality by omitting the Y coordinate. This works because only two points on the curve share the same X coordinate, meaning the 32-byte Y coordinate can be replaced with just a single bit indicating whether the point lies on what can be thought of as the “upper” or “lower” side of the curve.

No data is lost by compressing the public keys, as the Y coordinate can be easily recalculated from the X coordinate using minimal CPU resources. Both compressed and uncompressed public keys are well-documented in the secp256k1 standard and are supported by default in the widely-used OpenSSL library.

Because compressed public keys are simple to use and nearly halve the blockchain space required to store public keys for every spent output, they have become the default in BitcoinEvo Core. This is the recommended default for all BitcoinEvo software as well.

However, BitcoinEvo Core versions prior to 0.6 used uncompressed keys, which introduces some complexity. The hashed form of an uncompressed key differs from that of a compressed key, so the same key generates two different P2PKH addresses. Furthermore, the key must be submitted in the correct format within the signature script to match the hash found in the previous output’s pubkey script.

To address this, BitcoinEvo Core uses different identifier bytes to help programs distinguish how keys should be handled:

  • Private keys intended for use with compressed public keys have 0x01 appended to them before being encoded in Base-58. (See the private key encoding section above.)

  • Uncompressed public keys start with the prefix 0x04, while compressed public keys begin with either 0x03 or 0x02, depending on whether they are above or below the curve’s midpoint. These prefixes are part of the official secp256k1 specification.

Hierarchical Deterministic Key Creation

The hierarchical deterministic (HD) key creation and transfer protocol greatly simplifies wallet backups, removes the need for constant communication between programs using the same wallet, allows for the creation of child accounts that can operate independently, and enables a parent account to monitor or control its children — even if a child account is compromised. Additionally, it splits each account into full-access and restricted-access parts, allowing untrusted users or programs to receive or monitor payments without being able to spend funds.

The HD protocol takes advantage of the ECDSA public key generation function, point(), which converts a large integer (the private key) into a point on a graph (the public key):

point(private_key) == public_key

Thanks to the nature of point(), it is possible to create a child public key by combining an existing parent public key with another public key generated from any integer (i). This child public key matches the one that would result from adding the integer (i) to the parent private key and then finding the remainder of that sum divided by a constant used by all BitcoinEvo software (p):

point((parent_private_key + i) % p) == parent_public_key + point(i)

This allows two or more independent programs, as long as they agree on a sequence of integers, to generate a series of unique child key pairs from a single parent key pair without needing further communication. The program responsible for distributing new public keys to receive payments can do so without any access to the private keys, making it safe to run on a less secure platform, such as a public web server. Child public keys can also derive their own child public keys (grandchild public keys) by repeating the same child key derivation steps:

point((child_private_key + i) % p) == child_public_key + point(i)

Whether generating child or further-descended public keys, a predictable sequence of integers would offer no more security than using a single public key for all transactions. Anyone who knows one child public key could calculate all others derived from the same parent public key. Instead, a random seed is used to deterministically generate the sequence of integers, ensuring that the relationship between child public keys remains hidden from anyone without access to the seed.

The HD protocol relies on a single root seed to create a hierarchy of child, grandchild, and other descended keys with deterministically-generated, unlinkable integers. Each child key also receives a deterministically-generated seed from its parent, called a chain code. This ensures that if one chain code is compromised, it doesn’t expose the entire hierarchy. Even if, for instance, a web-based public key distribution program is hacked, the master chain code can still be safely used.


Overview Of Hierarchical Deterministic Key Derivation

As shown above, HD key derivation relies on four key inputs:

  1. The parent private key and parent public key, which are standard uncompressed 256-bit ECDSA keys.
  2. The parent chain code, consisting of 256 bits of seemingly random data.
  3. The index number, a 32-bit integer that the program specifies.
In the typical form illustrated above, the parent chain code, parent public key, and index number are fed into a cryptographic hash function (HMAC-SHA512), which produces 512 bits of deterministically generated, seemingly random data. The rightmost 256 bits of this output are used to create a new child chain code, while the leftmost 256 bits are used as the integer value that will be combined with either the parent private key or public key to derive the corresponding child key.

  • child_private_key = (parent_private_key + left_hash_output) % G
  • child_public_key = point((parent_private_key + left_hash_output) % G)
  • child_public_key = point(child_private_key) = parent_public_key + point(left_hash_output)
By specifying different index numbers, one can generate multiple unique and unlinkable child keys from the same parent keys. Repeating this process using the child keys and the child chain code results in further unlinkable grandchild keys.

Since generating child keys requires both a key and a chain code, they are referred to together as the extended key. An extended private key shares the same chain code as its corresponding extended public key. The (top-level) master private key and master chain code are derived from random data, as depicted below.


Creating A Root Extended Key Pair

A root seed is generated from random data, which can be 128 bits, 256 bits, or 512 bits in size. This 128-bit minimum root seed is the only piece of information users need to back up in order to recreate every key generated by a specific wallet program with particular settings.

Warning: As of this writing, HD wallet programs are not fully compatible, so users must stick to the same HD wallet program with the same HD-related settings for a given root seed.

The root seed is hashed, resulting in 512 bits of seemingly random data, from which both the master private key and the master chain code are derived. These two together form the master extended private key. The master public key is generated from the master private key using the point() function. Along with the master chain code, this forms the master extended public key. The master extended keys operate just like other extended keys; their position at the top of the hierarchy is what makes them unique.

Hardened Keys

Hardened extended keys address a vulnerability found in standard extended keys. If an attacker obtains a normal parent chain code and public key, they could brute-force all child chain codes derived from it. Furthermore, if the attacker also gets hold of a private key at any descendant level (e.g., child, grandchild, or further), they could use the chain code to generate all private keys further down the hierarchy, as illustrated by the grandchild and great-grandchild generations in the diagram.


Cross-Generational Key Compromise

Even more concerning, an attacker could reverse the standard child private key derivation formula and subtract the parent chain code from a child private key to recover the parent private key, as shown in the illustration of the child and parent generations. This means that if an attacker gains access to an extended public key along with any private key derived from it, they could retrieve the parent private key and subsequently all other keys that descend from it.

Because of this vulnerability, the chain code portion of an extended public key must be better protected than regular public keys. Additionally, users should be strongly cautioned against exporting non-extended private keys to potentially untrustworthy environments.

This problem can be mitigated, with some tradeoffs, by adopting a hardened key derivation formula instead of the standard one.

In the standard key derivation formula (explained in the previous section), the index number, parent chain code, and parent public key are combined to generate both the child chain code and the integer value used to derive the child private key from the parent private key.


Creating Child Public Keys From An Extended Private Key

The hardened key derivation formula, as illustrated, combines the index number, parent chain code, and parent private key to produce the data needed to generate the child chain code and child private key. This approach prevents the creation of child public keys without access to the parent private key. In simpler terms, hardened child public keys cannot be derived from parent extended public keys.

As a result, hardened extended private keys are less flexible than normal extended private keys. However, they offer a critical security benefit by creating a firewall that blocks multi-level key derivation attacks. Since hardened child extended public keys cannot generate grandchild chain codes, compromising a parent extended public key cannot be leveraged alongside a compromised grandchild private key to generate great-grandchild extended private keys.

The HD protocol utilizes different index numbers to distinguish between normal and hardened key derivation. Index numbers from 0x00 to 0x7fffffff (0 to 2³¹-1) are used for normal key derivation, while index numbers from 0x80000000 to 0xffffffff generate hardened keys. To simplify descriptions, many developers use a prime symbol to denote hardened keys, so the first normal key (0x00) is labeled as 0, and the first hardened key (0x80000000) is labeled as 0′.

(BitcoinEvo developers typically use an apostrophe (‘) instead of the Unicode prime symbol for this purpose, a convention we will follow hereafter.)

This notation is often combined with slashes and prefixed by m or M to indicate the hierarchy and key type, with m representing a private key and M representing a public key. For example, m/0’/0/122′ refers to the 123rd hardened private child (by index number) of the first normal child (by index) of the first hardened child (by index) of the master private key. The following hierarchy illustrates the prime notation and the security firewalls created by hardened keys.


Example HD Wallet Tree Using Prime Notation



HD wallets following the BIP32 protocol only generate hardened child keys from the master private key (m) to ensure that a compromised child key does not jeopardize the master key. Since there are no normal child keys for master keys, the master public key is not used in HD wallets. For other keys, however, normal children can be generated, allowing the corresponding extended public keys to be utilized.

The HD protocol also outlines a serialization format for both extended private and public keys. For more information, refer to the wallet section in the developer reference or review BIP32 for a full description of the HD protocol specification.

Storing Root Seeds

In the HD protocol, root seeds consist of 128, 256, or 512 bits of random data, which must be backed up precisely. To make non-digital backup methods more convenient, such as memorization or handwriting, BIP39 provides a method for generating a 512-bit root seed from a mnemonic phrase composed of common, natural-language words. This phrase is derived from 128 to 256 bits of entropy and can optionally be protected with a passphrase.

The number of words generated in the mnemonic phrase corresponds to the amount of entropy used:

Entropy Bits Words
128 12
160 15
192 18
224 21
256 24


The passphrase can be of any length and is appended to the mnemonic phrase. The mnemonic and passphrase are then hashed together 2,048 times using HMAC-SHA512, resulting in a 512-bit seed that appears random. Since any input to the hash function produces a seemingly-random 512-bit seed, there is no inherent way to confirm whether the correct passphrase was entered, allowing users to safeguard a seed even under duress.

For further implementation details, please refer to BIP39.

Loose-Key Wallets

Loose-Key wallets, also known as “Just a Bunch Of Keys” (JBOK), are an outdated form of wallet that originated from the BitcoinEvo Core client wallet. The BitcoinEvo Core wallet would automatically generate 100 private key/public key pairs using a Pseudo-Random-Number Generator (PRNG) for future use.

These unused private keys were stored in a virtual “key pool,” and new keys were generated whenever one of the previously generated keys was used, ensuring the pool always contained 100 unused keys. (If the wallet was encrypted, new keys would only be generated when the wallet was unlocked.)

Backing up this type of wallet proved to be challenging because new private keys were generated frequently, and users had to manually back up their wallets to include the newly created keys. If a newly generated key pair was created, used, and then lost before a backup was made, the stored satoshis could be permanently lost. Many older mobile wallets followed a similar pattern, generating new private keys only upon user request.

This type of wallet is being phased out and is no longer recommended due to the difficulties associated with backing up keys.