CashAddr encoding
CashAddr encoding is an address format used in Nexa. This is a Base32 encoding format. The goal of the encoding is to make it easier to copy and to share information, by using a QR code for instance.
A Cash Address consists of:
- A prefix which is human-readable.
- A separator (
:
). - A Base32 payload which contains a version byte and the data (or hash).
- A Base32 checksum.
This format reuses the work done for Bech32 (see BIP173) and is similar in some aspects, but improves on others. See the original specification for more details.
Prefix
The prefix is a human-readable part of the address which indicates the network on which the addess is valid, or the metaprotocol used. It can only contain ASCII characters.
There are 3 prefixes used in Bitcoin Cash to indicate the network:
Network | Prefix |
---|---|
Mainnet | nexa |
Testnet | nexatest |
Regtest | nexareg |
The prefix can also indicate for which metaprotocol the address must be used.
The prefix is always followed by the separator :
.
When presented to users, the prefix and the separator may be omitted as it is part of the checksum computation. Due to this checksum difference, an address (without the prefix) on one blockchain is extremely unlikely to be a valid address on a different one.
Address Lengths
Nexa cashaddr encoding has no restriction on address length.
Base32
CashAddr uses Base32 to encode information. The symbols used in CashAddr Base32 are the lowercase alphanumeric characters excluding 1
, b
, i
, and o
. Uppercase characters are also valid to enable efficient QR code encoding (see spec). However, any mixture of lowercase and uppercase characters must be rejected.
Base32 alphabet:
qpzry9x8gf2tvdw0s3jn54khce6mua7l
Base32 symbol chart:
Value | Character | Value | Character |
---|---|---|---|
0 | q | 16 | s |
1 | p | 17 | 3 |
2 | z | 18 | j |
3 | r | 19 | n |
4 | y | 20 | 5 |
5 | 9 | 21 | 4 |
6 | x | 22 | k |
7 | 8 | 23 | h |
8 | g | 24 | c |
9 | f | 25 | e |
10 | 2 | 26 | 6 |
11 | t | 27 | m |
12 | v | 28 | u |
13 | d | 29 | a |
14 | w | 30 | 7 |
15 | 0 | 31 | l |
Checksum
The checksum is a 40 bits Bose–Chaudhuri–Hocquenghem code (BCH) code defined over the finite field GF(2^5). It ensures the detection of up to 6 errors in the address and 8 in a row. Combined with the length check, this provides very strong guarantee against errors.
The checksum is computed by the following polymod
function (written in Python):
def polymod(values):
c = 1
for d in values:
c0 = c >> 35
c = ((c & 0x07ffffffff) << 5) ^ d
if (c0 & 0x01):
c ^= 0x98f2bc8e61
if (c0 & 0x02):
c ^= 0x79b76d99e2
if (c0 & 0x04):
c ^= 0xf33e5fb3c4
if (c0 & 0x08):
c ^= 0xae2eabe2a8
if (c0 & 0x10):
c ^= 0x1e4f43e470
return c ^ 1
where &
is the bitwise AND operator, ^
is the bitwise XOR operator, and >>
is the bitwise right shift.
Version bytes
The length portion (lowest 3 bits) of the version byte as defined in the cashaddr specification is obsolete, but Nexa version bytes set this value to 0 for now.
The version byte for script template address types, the first byte MUST be 152. This begins each address with "n", and defines the contents as specified below. The version byte for group (token) identifiers the first byte MUST be 88. This begins each address with "t". The version byte for legacy (pay-to-pubkey-hash) address types, the first byte MUST be 0. This is as defined in the CashAddr spec.
Address Contents
Script Templates
In script templates, the address contains the serialized "locking script" data.
This "locking script" is first serialized as a CScript, just like it would appear in a transaction output. Then it is network-serialized (which in this case means in a length then data format, where the length is specified as a "compact size"). Note that network serialization and script serialization are DIFFERENT for larger buffer sizes. Do not "PUSH" the locking script to make an address
It is allowed to network-serialize other data after the script template data. This data should be ignored in the construction of the actual transaction output by "general" clients. However it could be used to communicate application or protocol-specific data.
These bytes form the "data" field in the section "Encoding a Nexa address" below.
Group Identifier
The 256 bit group identifier, as created during the group genesis transaction.
Pay-to-public-key hash
the 160 bit hash of the public key (the same as Bitcoin/Bitcoin Cash).
Encoding a Nexa address
To encode an address with CashAddr, follow the steps described below:
-
Take the address data, which is the hash of a public key (P2PKH) or group, or serialized output template (script templates).
-
Concatenate the version byte and the data bytes together (bytewise):
payload = version || data
-
Divide the payload into chunks of 5 bits. The payload is padded to the right with zero bits to complete any unfinished chunk at the end.
-
Compute the checksum by applying
polymod
to the following values:a. The lower 5 bits of each character of the prefix. For letters, this corresponds to their position in the alphabet.
b. A zero for the separator (5 zero bits).
c. The payload.
d. Eight zeros as a template for the checksum.
-
Encode each chunk of the payload and each chunk of the checksum with Base32.
Examples
Ungrouped Pay-to-public-key-template (P2PKT) Form
OP_0 # No group OP_1 # Well known template 1 PUSH Hash160(Script(PUSH pubkey)) [Optional: TBD additional data (do not rely on the size to identify this address form)]
Example
nexa:nqtsq5g5w6syq5aa5z5ghkj3w7ux59wrk204txrn64e2gs92
Grouped, Unspecified Token Amount, Pay-to-public-key-template (GP2PKT) Form
PUSH GroupId
OP_0 # Unspecified token amount
OP_1 # Well known template 1
PUSH Hash160(Script(PUSH pubkey))
[Optional: TBD additional data (do not rely on the size to identify this address form)]
Example
nexa:nqazqy3uqsp4j0zyyufqzy65qc2u9vvm2jthyqgzqvzq2ps8pqys5zcvqgqqq5g5w6syq5aa5z5ghkj3w7ux59wrk204txrn92xzqzsu
Ungrouped Pay-To-Contract-Args-Template (P2CAT) Form
OP_0 # No group
PUSH Hash160/256(Script(... your contract...))
PUSH Hash160/256(Script(PUSH your args ...))
[Optional: PUSH visible args]...
[Optional: TBD additional data]...
Example
nexa:nq4sq9rk5pq980dq4z9a55thhp4ptsajna2esuc5zg7qgq6e83zzwyspzd2qv9wzkxd4f9mjwp6hsdfn
Grouped, Pay-To-Contract-Args-Template (GP2CAT) Form
PUSH GroupId
OP_0 # Unspecified token amount
PUSH Hash160/256(Script(... your contract...))
PUSH Hash160/256(Script(PUSH your args ...))
[Optional: PUSH visible args]...
[Optional: TBD additional data]...
Example
nexa:np9sq9rk5pq980dq4z9a55thhp4ptsajna2esuc5zg7qgq6e83zzwyspzd2qv9wzkxd4f9mjzg7qgq6e83zzwyspzd2qv9wzkxd4f9mjqypqxpq9qcrsszg2pvxq3p2q9kaa
Ungrouped Pay-To-Contract-Template (P2CT) Form (no args)
OP_0 # No group
PUSH Hash160/256(Script(... your contract...))
OP_0 # No args
[Optional: PUSH visible args]...
[Optional: TBD additional data]...
Example
nexa:nqtsq9rk5pq980dq4z9a55thhp4ptsajna2esucqqj42vk56
Bitcoin Cash (or similar P2PKH for Nexa)
The steps to encode a P2PKH address which is valid on the Bitcoin Cash main network are:
-
Take the address data, i.e., the 20-byte hash of the public key:
211b74ca4686f81efda5641767fc84ef16dafe0b
-
Concatenate the version byte (here
0x00
) and the data bytes together to get the payload:2. Divide the payload into chunks of 5 bits. In this example, the payload is 168-bit long; therefore, it is padded to the right with 2 zero bits to complete the last chunk. The resulting chunks are:00211b74ca4686f81efda5641767fc84ef16dafe0b
[ 0, 0, 16, 17, 22, 29, 6, 10, 8, 26, 3, 15, 16, 7, 23, 29, 20, 21, 18, 1, 14, 25, 31, 28, 16, 19, 23, 17, 13, 22, 23, 30, 1, 12 ]
-
Compute the checksum by applying
polymod
to the concatenation of:a. The lower 5 bits of each character of the prefix
bitcoincash
:[ 2, 9, 20, 3, 15, 9, 14, 3, 1, 19, 8 ]
b. A zero for the separator:
[ 0 ]
c. The payload chunks:
[ 0, 0, 16, 17, 22, 29, 6, 10, 8, 26, 3, 15, 16, 7, 23, 29, 20, 21, 18, 1, 14, 25, 31, 28, 16, 19, 23, 17, 13, 22, 23, 30, 1, 12 ]
d. The template of the checksum:
[ 0, 0, 0, 0, 0, 0, 0, 0 ]
The checksum is:
[ 28, 10, 17, 3, 2, 3, 3, 28 ]
-
Encoded with Base32, the payload and the checksum are, respectively,
qqs3kax2g6r0s8ha54jpwelusnh3dkh7pv
andu23rzrru
. The resulting address is:bitcoincash:qqs3kax2g6r0s8ha54jpwelusnh3dkh7pvu23rzrru