Skip to content

Altchain Encrypted Private Keys

Skaht edited this page Oct 5, 2015 · 38 revisions

There is no limit to the potential deviation of an altcoin from Bitcoin standards, so its not possible for us to support all altcoins generally. We do strive to support altchains. In other words, to the extent that an alt uses Bitcoin standards, but with distinct consensus rules, we intend to support it.

It is our goal to support altchains without a rebuild of any library, so any compiled libbitcoin binary supports them all. This cannot be generally extended to consensus deviations so it is our intent to implement pluggable consensus modules. We currently support testnet but this will not be entirely free of conditional compilation until the version3 release.

These considerations drive the outcome on this question. There are three base58check (serializable) primitives associated with BIP-38, which libbitcoin refers to as follows:

  • private_key : encrypted private key
  • public_key : encrypted public key
  • token : intermediate passphrase string

In accordance with BIP-38 these have the following prefix values:

namespace prefix
{
    // This prefix results in the prefix "6P" in the base58 encoding.
    static const data_chunk private_key
    {
        0x01, 0x42
    };

    // This prefix results in the prefix "6P" in the base58 encoding.
    static const data_chunk private_key_multiplied
    {
        0x01, 0x43
    };

    // This prefix results in the prefix "cfrm" in the base58 encoding.
    static const data_chunk public_key
    {
        0x64, 0x3b, 0xf6, 0xa8, 0x9a
    };

    // This prefix results in the prefix "passphrase" in the base58 encoding.
    static const data_chunk lot_token
    {
        0x2c, 0xe9, 0xb3, 0xe1, 0xff, 0x39, 0xe2, 0x51
    };

    // This prefix results in the prefix "passphrase" in the base58 encoding.
    static const data_chunk plain_token
    {
        0x2c, 0xe9, 0xb3, 0xe1, 0xff, 0x39, 0xe2, 0x53
    };
}

The first byte of each of these is the base58check version. This of course should not be confused with a payment address base58check version. BIP-38 serializes payment addresses before hashing. So there is also a payment address version affecting each of the three primitives. Notably the compression option for ec public keys also affects these artifacts.

BIP-38 carries the compression flag through the encoding. As a consequence there is no need to have knowledge of the compression value used in creation of the keys in order to decrypt the keys. This is not the case with the payment address version. Three options exist that are consistent with BIP-38:

  1. The payment address version is always Bitcoin mainnet 0x01 (with compression specified at encryption time).
  2. The payment address version and compression are specified at encryption time, and the correct payment address version must also be provided at decryption time. This apples to decryption of both the private key and the public key if one desires to reconstitute a payment address - as envisioned by BIP-38.
  3. The payment address version and compression are specified only at encryption time.

The first doesn’t even support testnet. The second is poor from a user scenario perspective. The third provides support for altchains that is consistent with BIP-38 behavior for Bitcoin mainnet. There are two ways to implement this option:

  1. Hard code a partial mapping between well-known payment address versions and corresponding encrypted key prefixes, and deploy universal code changes as this mapping evolves to fill the 256 bit domain.
  2. Define a deterministic bidirectional mapping between all payment address versions and the encrypted key prefixes.

BIP-38 Suggestions Regarding Altchains

Alt-chain implementers should exploit the address hash for this purpose. Since each operation in this proposal involves hashing a text representation of a coin address which (for Bitcoin) includes the leading '1', an alt-chain can easily be denoted simply by using the alt-chain's preferred format for representing an address. Alt-chain implementers may also change the prefix such that encrypted addresses do not start with "6P". [hyperlink]

The above appears to assume that altchains will hard code the payment address version into applications. Otherwise the scenario is degraded for altchain usage, as described previously. Given that it is a requirement for libbitcoin to avoid compilation for specific altchains, this assumption does not hold.

Proposal

Given that encrypted keys already have a dependency on payment address versions there appears to be no reason to support a mapping between these versions. A deterministic mapping is straightforward to implement and makes tooling immune to evolution of the published address version and encrypted key prefix domains.

The payment address version could simply be coupled to the base58check version byte for a corresponding encrypted private key. This however is cosmetically undesirable, as the prefix characters and constant encoded length are preserved by varying the last byte of the prefix, as opposed to the first.

Therefore we mutate the last byte of the prefix by two's compliment addition of the payment address version to the value specified by BIP38. The payment address version is therefore retrievable using subtraction.

Backward Compatibility

Because BIP38 assumes Bitcoin mainnet, the only payment address version expected is zero (0). As such there is no impact on existing encodings or tooling to support pre-existing addresses.

Cosmetic Inflexibility

A possible problem is the inability to choose the first couple of characters in encrypted keys independently from the payment address version for the same altchain. This seems not terribly important however.

Limited Payment Address Version Domain

It is also true that there is a finite domain of 256 values for the payment address version. However this issue cannot be resolved by expanding the domain of encrypted private keys that are coupled to that domain. It seems preferable to attach any expansion to the encrypted key domain to a corresponding expansion of the payment address domain.

Effect on Serialized Artifacts

The implementation as described has no impact on intermediate passphrase token serialization. This artifact retains its encoded prefix of "passphrase" but does not incorporate the address version, and as such this value will be chain ambiguous.

BIP-38 declares the prefix 6P for the private_key, where the P represents password protection and 6 is intended to deconflict with typical WIF keys. This prefix will vary by payment address version and is predicable for a given address version, within a narrow range.

BIP-38 declares the natural language abbreviation prefix cfrm for the public_key. This prefix is preserved, and the three characters following the confirmation also vary by payment address within a narrow range.

The limited encoded prefix ambiguity is similar to that which exists for payment addresses. For example, a testnet payment address begins with either m or n. Similarly the testnet private_key can begins with either 8E or 8F.

BIP38 Intermediate Code Limitations

In BIP38 terminology, an intermediate code is a token generated by an owner and supplied to a printer. The token can incorporate arbitrary lot and sequence values for required incorporation into printer-generated keys.

However the token cannot carry the owner's required address constraints, specifically version but also compression. This limits the utility of the token. A printer can generate keys for addresses that pass validation via the owner's passphrase but are nonetheless not usable by the owner due to compression. The printer is in control of the public key compression state in generated encrypted keys.

Similarly, in the proposed version mapping it is not possible for the owner to constrain the address version. As with key compression, it can only be validated by obtaining the value and explicitly comparing it to what is desired. This could be resolved by modifying the proposal to hash compression and version information into the intermediate code. This should be combined with the addition of a flag byte to hold the compression and lot/sequence context, and an address mapping scheme identical to that proposed above (i.e. in the last byte of the prefix).

Sample Map

0x00 -> 6P... cfrm38V...
0x01 -> 6Q... cfrm38Y...
0x02 -> 6R... cfrm38b...
0x03 -> 6S... cfrm38e...
0x04 -> 6T... cfrm38i...
0x05 -> 6U... cfrm38m...
0x06 -> 6V... cfrm38p...
0x07 -> 6W... cfrm38s...
0x08 -> 6X... cfrm38v...
0x09 -> 6Y... cfrm38y...
0x0a -> 6Z... cfrm393...
0x0b -> 6a... cfrm396...
0x0c -> 6b... cfrm399...
0x0d -> 6c... cfrm39C...
0x0e -> 6d... cfrm39F...
0x0f -> 6e... cfrm39J...
0x10 -> 6f... cfrm39M...
0x11 -> 6g... cfrm39R...
0x12 -> 6h... cfrm39U...
0x13 -> 6i... cfrm39X...
0x14 -> 6j... cfrm39a...
0x15 -> 6k... cfrm39d...
0x16 -> 6m... cfrm39g...
0x17 -> 6n... cfrm39k...
0x18 -> 6o... cfrm39o...
0x19 -> 6o... cfrm39r...
0x1a -> 6p... cfrm39u...
0x1b -> 6q... cfrm39x...
0x1c -> 6r... cfrm3A1...
0x1d -> 6s... cfrm3A4...
0x1e -> 6t... cfrm3A8...
0x1f -> 6u... cfrm3AB...
0x20 -> 6v... cfrm3AE...
0x21 -> 6w... cfrm3AH...
0x22 -> 6x... cfrm3AL...
0x23 -> 6y... cfrm3AP...
0x24 -> 6z... cfrm3AT...
0x25 -> 71... cfrm3AW...
0x26 -> 72... cfrm3AZ...
0x27 -> 73... cfrm3Ac...
0x28 -> 74... cfrm3Af...
0x29 -> 75... cfrm3Ai...
0x2a -> 76... cfrm3Am...
0x2b -> 77... cfrm3Aq...
0x2c -> 78... cfrm3At...
0x2d -> 79... cfrm3Aw...
0x2e -> 7A... cfrm3Az...
0x2f -> 7B... cfrm3B3...
0x30 -> 7C... cfrm3B6...
0x31 -> 7D... cfrm3BA...
0x32 -> 7E... cfrm3BD...
0x33 -> 7F... cfrm3BG...
0x34 -> 7G... cfrm3BK...
0x35 -> 7H... cfrm3BN...
0x36 -> 7J... cfrm3BR...
0x37 -> 7K... cfrm3BU...
0x38 -> 7K... cfrm3BY...
0x39 -> 7L... cfrm3Bb...
0x3a -> 7M... cfrm3Be...
0x3b -> 7N... cfrm3Bh...
0x3c -> 7P... cfrm3Bk...
0x3d -> 7Q... cfrm3Bo...
0x3e -> 7R... cfrm3Bs...
0x3f -> 7S... cfrm3Bv...
0x40 -> 7T... cfrm3By...
0x41 -> 7U... cfrm3C2...
0x42 -> 7V... cfrm3C5...
0x43 -> 7W... cfrm3C8...
0x44 -> 7X... cfrm3CB...
0x45 -> 7Y... cfrm3CF...
0x46 -> 7Z... cfrm3CJ...
0x47 -> 7a... cfrm3CM...
0x48 -> 7b... cfrm3CQ...
0x49 -> 7c... cfrm3CT...
0x4a -> 7d... cfrm3CW...
0x4b -> 7e... cfrm3Ca...
0x4c -> 7f... cfrm3Cd...
0x4d -> 7g... cfrm3Cg...
0x4e -> 7h... cfrm3Cj...
0x4f -> 7i... cfrm3Cn...
0x50 -> 7j... cfrm3Cq...
0x51 -> 7k... cfrm3Ct...
0x52 -> 7m... cfrm3Cx...
0x53 -> 7n... cfrm3D1...
0x54 -> 7o... cfrm3D4...
0x55 -> 7p... cfrm3D7...
0x56 -> 7q... cfrm3DA...
0x57 -> 7q... cfrm3DD...
0x58 -> 7r... cfrm3DH...
0x59 -> 7s... cfrm3DL...
0x5a -> 7t... cfrm3DP...
0x5b -> 7u... cfrm3DS...
0x5c -> 7v... cfrm3DV...
0x5d -> 7w... cfrm3DY...
0x5e -> 7x... cfrm3Db...
0x5f -> 7y... cfrm3Df...
0x60 -> 7z... cfrm3Di...
0x61 -> 81... cfrm3Dm...
0x62 -> 82... cfrm3Dp...
0x63 -> 83... cfrm3Ds...
0x64 -> 84... cfrm3Dv...
0x65 -> 85... cfrm3Dz...
0x66 -> 86... cfrm2z7...
0x67 -> 87... cfrm2zA...
0x68 -> 88... cfrm2zE...
0x69 -> 89... cfrm2zH...
0x6a -> 8A... cfrm2zL...
0x6b -> 8B... cfrm2zP...
0x6c -> 8C... cfrm2zS...
0x6d -> 8D... cfrm2zV...
0x6e -> 8E... cfrm2zY...
0x6f -> 8F... cfrm2zc...
0x70 -> 8G... cfrm2zf...
0x71 -> 8H... cfrm2zi...
0x72 -> 8J... cfrm2zm...
0x73 -> 8K... cfrm2zp...
0x74 -> 8L... cfrm2zs...
0x75 -> 8M... cfrm2zw...
0x76 -> 8N... cfrm2zz...
0x77 -> 8N... cfrm313...
0x78 -> 8P... cfrm316...
0x79 -> 8Q... cfrm319...
0x7a -> 8R... cfrm31C...
0x7b -> 8S... cfrm31F...
0x7c -> 8T... cfrm31K...
0x7d -> 8U... cfrm31N...
0x7e -> 8V... cfrm31R...
0x7f -> 8W... cfrm31U...
0x80 -> 8X... cfrm31X...
0x81 -> 8Y... cfrm31a...
0x82 -> 8Z... cfrm31e...
0x83 -> 8a... cfrm31h...
0x84 -> 8b... cfrm31k...
0x85 -> 8c... cfrm31o...
0x86 -> 8d... cfrm31r...
0x87 -> 8e... cfrm31u...
0x88 -> 8f... cfrm31x...
0x89 -> 8g... cfrm322...
0x8a -> 8h... cfrm325...
0x8b -> 8i... cfrm328...
0x8c -> 8j... cfrm32B...
0x8d -> 8k... cfrm32E...
0x8e -> 8m... cfrm32H...
0x8f -> 8n... cfrm32M...
0x90 -> 8o... cfrm32Q...
0x91 -> 8p... cfrm32T...
0x92 -> 8q... cfrm32W...
0x93 -> 8r... cfrm32Z...
0x94 -> 8s... cfrm32c...
0x95 -> 8t... cfrm32f...
0x96 -> 8t... cfrm32j...
0x97 -> 8u... cfrm32n...
0x98 -> 8v... cfrm32q...
0x99 -> 8w... cfrm32t...
0x9a -> 8x... cfrm32w...
0x9b -> 8y... cfrm32z...
0x9c -> 8z... cfrm334...
0x9d -> 91... cfrm337...
0x9e -> 92... cfrm33A...
0x9f -> 93... cfrm33D...
0xa0 -> 94... cfrm33G...
0xa1 -> 95... cfrm33K...
0xa2 -> 96... cfrm33N...
0xa3 -> 97... cfrm33S...
0xa4 -> 98... cfrm33V...
0xa5 -> 99... cfrm33Y...
0xa6 -> 9A... cfrm33b...
0xa7 -> 9B... cfrm33e...
0xa8 -> 9C... cfrm33h...
0xa9 -> 9D... cfrm33m...
0xaa -> 9E... cfrm33p...
0xab -> 9F... cfrm33s...
0xac -> 9G... cfrm33v...
0xad -> 9H... cfrm33y...
0xae -> 9J... cfrm342...
0xaf -> 9K... cfrm345...
0xb0 -> 9L... cfrm349...
0xb1 -> 9M... cfrm34C...
0xb2 -> 9N... cfrm34F...
0xb3 -> 9P... cfrm34J...
0xb4 -> 9Q... cfrm34M...
0xb5 -> 9Q... cfrm34Q...
0xb6 -> 9R... cfrm34U...
0xb7 -> 9S... cfrm34X...
0xb8 -> 9T... cfrm34a...
0xb9 -> 9U... cfrm34d...
0xba -> 9V... cfrm34g...
0xbb -> 9W... cfrm34j...
0xbc -> 9X... cfrm34n...
0xbd -> 5G... cfrm34r...
0xbe -> 5H... cfrm34u...
0xbf -> 5J... cfrm34x...
0xc0 -> 5K... cfrm351...
0xc1 -> 5L... cfrm354...
0xc2 -> 5M... cfrm357...
0xc3 -> 5N... cfrm35B...
0xc4 -> 5P... cfrm35E...
0xc5 -> 5Q... cfrm35H...
0xc6 -> 5R... cfrm35L...
0xc7 -> 5S... cfrm35P...
0xc8 -> 5T... cfrm35S...
0xc9 -> 5U... cfrm35V...
0xca -> 5V... cfrm35Z...
0xcb -> 5W... cfrm35c...
0xcc -> 5X... cfrm35f...
0xcd -> 5Y... cfrm35i...
0xce -> 5Z... cfrm35m...
0xcf -> 5a... cfrm35p...
0xd0 -> 5b... cfrm35t...
0xd1 -> 5c... cfrm35w...
0xd2 -> 5d... cfrm35z...
0xd3 -> 5e... cfrm363...
0xd4 -> 5f... cfrm366...
0xd5 -> 5g... cfrm369...
0xd6 -> 5h... cfrm36C...
0xd7 -> 5i... cfrm36G...
0xd8 -> 5j... cfrm36K...
0xd9 -> 5k... cfrm36N...
0xda -> 5m... cfrm36R...
0xdb -> 5m... cfrm36U...
0xdc -> 5n... cfrm36X...
0xdd -> 5o... cfrm36b...
0xde -> 5p... cfrm36e...
0xdf -> 5q... cfrm36h...
0xe0 -> 5r... cfrm36k...
0xe1 -> 5s... cfrm36o...
0xe2 -> 5t... cfrm36r...
0xe3 -> 5u... cfrm36u...
0xe4 -> 5v... cfrm36y...
0xe5 -> 5w... cfrm372...
0xe6 -> 5x... cfrm375...
0xe7 -> 5y... cfrm378...
0xe8 -> 5z... cfrm37B...
0xe9 -> 61... cfrm37E...
0xea -> 62... cfrm37J...
0xeb -> 63... cfrm37M...
0xec -> 64... cfrm37Q...
0xed -> 65... cfrm37T...
0xee -> 66... cfrm37W...
0xef -> 67... cfrm37Z...
0xf0 -> 68... cfrm37d...
0xf1 -> 69... cfrm37g...
0xf2 -> 6A... cfrm37j...
0xf3 -> 6B... cfrm37n...
0xf4 -> 6C... cfrm37q...
0xf5 -> 6D... cfrm37t...
0xf6 -> 6E... cfrm37w...
0xf7 -> 6F... cfrm381...
0xf8 -> 6G... cfrm384...
0xf9 -> 6H... cfrm387...
0xfa -> 6H... cfrm38A...
0xfb -> 6J... cfrm38D...
0xfc -> 6K... cfrm38G...
0xfd -> 6L... cfrm38L...
0xfe -> 6M... cfrm38P...
0xff -> 6N... cfrm38S...

See Also

Libbitcoin Menu

Clone this wiki locally