Creating and Spending p2pk utxos using Bitcoin Core (and a little python)

Diane Reynolds
Jun 4, 2017 · 4 min read

In a previous article, I explained how bitcoin transactions could use less block space (and so save on fees) by using p2pk utxos (unspent transaction outputs). The most common type of “bitcoin address” is one for p2pkh utxos, encoding the 20 byte hash of a public key along with a 4 byte checksum. There currently is no notion of an “address” for p2pk utxos. However, as pointed out by killerstorm on reddit, such a notion of address could of course be defined and used. In this article, I will describe a candidate notion of a “p2pk address” and give python code for computing and using p2pk addresses. The python code creates unsigned transactions, expecting users to use Bitcoin Core to inspect, sign and send such transactions.

BIP 173 describes “Bech32” encoding and how it can be used to describe Segregated Witness utxos. Pieter Wuille has a corresponding git repo for bech32, including a reference implementation in python (along with other languages). The python code includes functions for encoding and decoding bech32 addresses.

The git repo bech32p2pkaddress builds on Wuille’s python implementation of bech32 to support a proposed p2pk address. All bech32 addresses start with a human-readable prefix separated from the encoded data by a “1.” We have chosen to use a prefix of “pk” for p2pk addresses, so all such addresses begin with “pk1.” The rest of the address encodes the (compressed, 33 byte) public key and a 4 byte checksum.

As an example, consider the pubkey 030e7061b9fb18571cf2441b2a7ee2419933ddaa423bc178672cd11e87911616d1. Using the python code in computep2pkaddr.py we can obtain the corresponding bech32 p2pk address by calling

python computepkaddr.py 030e7061b9fb18571cf2441b2a7ee2419933ddaa423bc178672cd11e87911616d1

giving the “p2pk address”

pk1qv88qcdelvv9w88jgsdj5lhzgxvn8hd2ggauz7r89ng3apu3zctdzgprkqg

The code in sendtopk.py can be used to create an unsigned transaction spending to p2pk “addresses.” (The “address” is purely for the interface. The binary representation of the resulting transaction only contains the script with the public key, not the “address.”) For the moment, sendtopk.py can only send to p2pk addresses. That is, one cannot mix p2pk and p2pkh outputs (yet).

Consider the following example spending from a (p2pkh) utxo to a new p2pk utxo:

python sendtopk.py ‘[{“txid”:”a491517c28d7eee4e175f47d3235b105576d35e7117642a997cd51c2526cb00c”,”vout”:6}]’ ‘{“pk1qv88qcdelvv9w88jgsdj5lhzgxvn8hd2ggauz7r89ng3apu3zctdzgprkqg”:0.00179716}’

This yields the unsigned tx

01000000010cb06c52c251cd97a9427611e7356d5705b135327df475e1e4eed7287c5191a40600000000010000000104be0200000000002321030e7061b9fb18571cf2441b2a7ee2419933ddaa423bc178672cd11e87911616d1ac00000000

This hex version of the binary data is not intended to be human readable. However, in Bitcoin Core the command decoderawtransaction can be used to check that the transaction is what was intended.

Here the user can check that the output has the correct value, is of type “pubkey” and that the correct public key is in the script (by inspecting “asm”).

Note that Bitcoin Core shows the p2pkh address 1CjRf1RMrTwyGoBHDbqzXERhVFkPyowt8i as the recipient of the output. This is the p2pkh address corresponding to public key, and most (all?) block explorers will show the p2pk output as arriving at the corresponding address, even though the utxo is not actually a p2pkh utxo.

Bitcoin Core can then be used to sign and broadcast the transaction using signrawtransaction and sendrawtransaction.

The transaction can be seen on blockchain.info here. The transaction (spending one p2pkh utxo to one p2pk utxo) is 202 bytes.

Spending the p2pk utxo is easier. While Bitcoin Core does not provide support for easily creating p2pk utxos, signrawtransaction will sign transactions spending p2pk utxos.

Spending a p2pk utxo using Bitcoin Core

The transaction spending the p2pk utxo to a single p2pkh utxo can be seen here. Note that this transaction is only 158 bytes, 78% the size of the first transaction. The same satoshis-per-byte were used for fees in both txs, and the result was that the first transaction required $1.28 worth of btc in fees and the second required only $0.99 worth of btc in fees.

This demonstration shows two things. First of all, the use of p2pk utxos does not mean we must give up addresses with checksums. We simply need to come to some agreement about a format. Secondly, even without coming to such an agreement, it is possible to make use of p2pk utxos already, assuming one is willing to make use of command line tools and Bitcoin Core commands.

Diane Reynolds

Written by

some logic, some crypto, some math