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:
:
).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.
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.
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 |
The checksum is a 40 bits 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.
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 addresses must begin with 152 (19<<3).
The version byte for groups must begin with 88 (11<<3).
The version byte for legacy pay-to-public-key-hash is the same as Bitcoin/Bitcoin Cash, or 0.
The serialized output locking data “script”.
The 256 bit group identifier, as created during the group genesis transaction.
the 160 bit hash of the public key (the same as Bitcoin/Bitcoin Cash).
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.
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
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
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
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
OP_0 # No group
PUSH Hash160/256(Script(… your contract…))
OP_0 # No args
[Optional: PUSH visible args]…
[Optional: TBD additional data]…
nexa:nqtsq9rk5pq980dq4z9a55thhp4ptsajna2esucqqj42vk56
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
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
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
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
OP_0 # No group
PUSH Hash160/256(Script(… your contract…))
OP_0 # No args
[Optional: PUSH visible args]…
[Optional: TBD additional data]…
nexa:nqtsq9rk5pq980dq4z9a55thhp4ptsajna2esucqqj42vk56
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:
00211b74ca4686f81efda5641767fc84ef16dafe0b
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:
[ 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
and u23rzrru
. The resulting address is:
bitcoincash:qqs3kax2g6r0s8ha54jpwelusnh3dkh7pvu23rzrru