Difference between revisions of "Public key to bitmessage address"

From Bitmessage Wiki
Jump to navigation Jump to search
(Add much more details)
Line 1: Line 1:
{{stub}}
+
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 [[Protocol specification#Variable length integer|var_int]]
 +
 
 +
A <code>+</code> 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 <code>pubSign + pubEnc</code>. Be sure to use the uncompressed keys (64 bytes per key, X9.62 format). (A)
 +
# <code>SHA512(A)</code>. (B)
 +
# <code>RIPEMD160(B)</code>. (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)
 +
# <code>Address Version + Stream number + E</code>. (F)
 +
# <code>SHA512(SHA512(F))</code>. Keep the first four bytes. (G)
 +
# <code>F + G</code>. (H)
 +
# <code>Base58_encode(H)</code>. (I)
 +
# <code>"BM-" + I</code>. (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 '''last''' 32 bytes of <code>SHA512(passphrase + var_int)</code> 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 ==
  
This page briefly describes, how to generate a Bitmessage Address from a public key.
+
Bitmessage's base58 encoding uses the following sequence (the same as Bitcoin's): "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".
The variable after the list is used to refer to the step later
+
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.
  
# Create a private and a public key for encryption and signing (resulting in 4 keys)
+
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.
# Merge the public part of the signing key and the encryption key together. (encoded in uncompressed X9.62 format) (A)
 
# Take the SHA512 hash of A. (B)
 
# Take the RIPEMD160 of B. (C)
 
# Repeat step 1-4 until you have a result that starts with a zero (Or two zeros, if you want a short address). (D)
 
# Remove the zeros at the beginning of D. (E)
 
# Put the stream number (as a [[Protocol specification#Variable length integer|var_int]]) in front of E. (F)
 
# Put the address version (as a [[Protocol specification#Variable length integer|var_int]]) in front of F. (G)
 
# Take a double SHA512 (hash of a hash) of G and use the first four bytes as a checksum, that you append to the end. (H)
 
# base58 encode H. (J)
 
# Put "BM-" in front J. (K)
 
  
K is your full address
+
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.
  
Note: 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 entire hashing and leading zero restrictions only apply to the public signing key, not the encryption key.

Revision as of 22:46, 3 August 2022

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.

  1. Create two key pairs using secp256k1, one for encryption and one for signing (privEnc, pubEnc, privSign, pubSign)
  2. Merge keys together using pubSign + pubEnc. Be sure to use the uncompressed keys (64 bytes per key, X9.62 format). (A)
  3. SHA512(A). (B)
  4. RIPEMD160(B). (C)
  5. 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)
  6. Remove all zeros at the beginning of D. (E)
  7. Address Version + Stream number + E. (F)
  8. SHA512(SHA512(F)). Keep the first four bytes. (G)
  9. F + G. (H)
  10. Base58_encode(H). (I)
  11. "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 last 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 entire hashing and leading zero restrictions only apply to the public signing key, not the encryption key.