Public key to bitmessage address
This page briefly describes, how to generate a Bitmessage Address from a public key. The variable after each step in the list is used to refer to the step later. Numbers used below are encoded as var_int
A +
in this documentation means concatenation.
- Create two key pairs using secp256k1, one for encryption and one for signing (privEnc, pubEnc, privSign, pubSign)
- Merge keys together using
pubSign + pubEnc
. Be sure to use the uncompressed keys (65 bytes per key, serialized X9.62 format). (A) SHA512(A)
. (B)RIPEMD160(B)
. (C)- Repeat step 1-4 until you have a result that starts with at least one zero. More zeros are permitted and cause a shorter address hash later. (D)
- Remove all zeros at the beginning of D. (E)
Address Version + Stream number + E
. (F)SHA512(SHA512(F))
. Keep the first four bytes. (G)F + G
. (H)Base58_encode(H)
. (I)"BM-" + I
. (J)
J is your full address. You want to store this together with privSign and privEnc somewhere. Note: The secp256k1 public keys don't need to be stored because they can be recreated again later from the private keys.
Deterministic address
Deterministic addresses are created by using the first 32 bytes of SHA512(passphrase + var_int)
as private key instead of randomly generating one.
The var_int for the signing key starts at 0, and for the encryption key at 1.
On every failed attempt to create an address, increment both integers by two and repeat the attempt. This means the integer for the signing key is always even,
and the one for the encryption key always odd and one bigger than the signing key.
Address validation
Remove the "BM-" at the beginning and Base58 decode the rest. Remove the last 4 bytes from the decoded data. Calculate SHA512 of the remaining address bytes and check if the first 4 bytes of the hash match the trimmed off 4 bytes.
Optional additional test: The address should start with two var_int values. Currently, only stream 1 is supported, and the address version should be 2-4.
Remarks
Bitmessage's base58 encoding uses the following sequence (the same as Bitcoin's): "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz". Many existing libraries for base58 do not use this ordering.
The BM- formatted address is never transmitted over the network. It's used to find the correct public key and decrypt it.
As you may have noticed, the address version and stream number are not part of the keys, this means it's technically possible to move an address between streams and versions, although the Base58 encoding makes the address look completely different each time.
The PyBitmessage client doesn't states how the passphrase is converted into bytes. This means using "äöü" as a passphrase will deliver different results across different operating systems because of how strings in python are handled internally. The API should not have this problem because the string is given using base64 encoding, which preserves the original binary data.
The entire hashing and leading zero restrictions only apply to the public signing key, not the encryption key.