What is a Payment Code (Bip47) and how can I make one with Electron Cash?

2019-01-28T11:49:14.000Z Honest Cash

Short Answer

Make a new standard account with Electron Cash, securely store the seed, and set the derivation path as below. This article about making wallets with Electron Cash might help if you are not familiar with the process already.

  • m/47'/145'/0' (to get payment code #0)
  • m/47'/0'/0' (also reasonable if you prefer the classic Bitcoin path)

When your new account is created and open, run this long piece of code in the console tab (view --> show console if you don't have the console tab):

import base58; print(base58.b58encode_check(bytes([0x47, 0x01, 0x00, *base58.b58decode_check(getmpk())[45:78], *base58.b58decode_check(getmpk())[13:45], *[0x00]*13])).decode())

Copy-Paste Note: Electron Cash's console only works if you paste on one line. So make sure when you paste it, it all appears on the ">>" line.

Security Note: I explain the code in detail later in the article. Please do not run this code in parts. This way your private data is never assigned to variables and should not be logged.

Done:

PM8TJTLJbPRGxSbc8EJi42Wrr6QbNSaSSVJ5Y3E4pbCYiTHUskHg13935Ubb7q8tx9GVbh2UuRnBc3WSyJHhUrw8KhprKnn9eDznYGieTzFcwQRya4GA

Go register at cashaccount.info by choosing a name and pasting that as your payment information. You can start to use it when Electron Cash or another wallet implements cash accounts and payment codes. You can use gitcash.io to put a bounty on the cash account issue or payment codes issue on github if you want it sooner than later.

What is a payment code?

From the Bip47 source:

This BIP defines a technique for creating a payment code which can be publicly
advertised and associated with a real-life identity without creating the loss of
security or privacy inherent to P2PKH address reuse.

Let's expand on that. If you go to cashaccount.info, you can use the cash account protocol to attach a name to an address. Then you can tell someone to send money to emergent_reasons#100 instead of bitcoincash:qz3aq0uhltztqyjy2esa0lshadg9pf87yu7yealu3a. It's a big usability improvement, and it's on-chain where anyone can register a name and anyone can look it up.

Now you can publicly send and receive money with emergent_reasons#100.

Very nice but very public. Enter the payment code.

Instead of publishing your name with an address, you go back to cashaccount.info and attach a name to a payment code. Then you can tell someone to send money to emergent_reasons#3646. Their wallet can see it is a payment code and instead of sending money, it uses its own payment code to send a special notification transaction. That notification creates a (very large) set of addresses that is private between the two of you. It is private because they look like any other address and no additional communication is required for both people to know all the addresses.

Now you can privately send and receive money with emergent_reasons#3646. It's not perfect privacy, but it is much better than a public address.

How can I make a payment code?

I will not explain the protocol itself because I will probably get something wrong. What I can do is use the python programming language to show you the steps from the final payment code back to the wallet seed. If you do not know how to use python, you can still follow because python is nice like that.

Print our payment code:

print(payment_code)

Base58 encoding is everywhere in bitcoin. Encode the payment code data into Base58 format:

import base58 payment_code = base58.b58encode_check(payment_code_data)

Assemble all the payment code data. Numbers are shown in hexadecimal format like "0xFF":

payment_code_data = bytes([
# 47 lets anyone looking at this data know that this is for bip47 0x47,
# 1 is the payment code version. There is also version 2 with different data
0x01,
# 0 shows that we are not using "bitmessage" for notifications.
0x00,
# next we unpack the 33-byte compressed public key with a "\*".
*public_key_bytes,
# then we unpack the 32-byte chain code
*chain_code_bytes,
# then we dump 13 bytes of zero in the space reserved for future features
*[0x00]*13
])

It's starts to get messy here if you are not familiar with Bip32. Get the public key and chain code from the extended public key.

public_key_bytes = extended_public_key_bytes[45:78]

chain_code_bytes = extended_public_key_bytes[13:45]

Get the extended public key (there is base58 encoding again). This can be done from any node in a Bip32 hierarchy. However according to Bip47 rules, we are making an account and getting the public key from the node at m/47'/145'/0'.

# getmpk() is a function built into the Electron Cash console

extended_public_key_bytes = base58.b58decode_check(getmpk())

Here is all the code in one place. Copy-paste will not work in the Electron Cash console since it has some limitations.

import base58

extended_public_key_bytes = base58.b58decode_check(getmpk())

public_key_bytes = extended_public_key_bytes[45:78]

chain_code_bytes = extended_public_key_bytes[13:45]

payment_code_data = bytes([

# 47 lets anyone looking at this data know that this is for bip47

0x47,

# 1 is the payment code version. There is also version 2 with different data

0x01,

# 0 shows that we are not using "bitmessage" for notifications.

0x00,

# next we unpack the 33-byte compressed public key with a "*".

*public_key_bytes,

# then we unpack the 32-byte chain code

*chain_code_bytes,

# then we dump 13 bytes of zero in the space reserved for future features

*[0x00]*13

])

payment_code = base58.b58encode_check(payment_code_data)

print(payment_code.decode())

Hope you enjoyed it. Please leave a comment!

Responses