Developers Home»Docs»SS58 Address Format

SS58 Address Format

SS58 is a simple address format designed for Substrate based chains. There's no problem with using other address formats for a chain, but this serves as a robust default. It is heavily based on Bitcoin's Base-58-check format with a few alterations.

The basic idea is a base-58 encoded value which can identify a specific account on the Substrate chain. Different chains have different means of identifying accounts. SS58 is designed to be extensible for this reason.

Format in detail

This page outlines the implementation of Ss58Codec in Substrate. Also of note is the canonical SS58 registry of address type mappings to various networks described below.

Basic format

The basic format conforms to:

base58encode ( concat ( <address-type>, <address>, <checksum> ) )

That is, the concatenated byte series of address type, address and checksum then passed into a base-58 encoder. The base58encode function is implemented exactly as defined in Bitcoin and IPFS, using the same alphabet as both.

Address type

The <address-type> is one or more bytes that describe the precise format of the following bytes.

Currently, there exist several valid values:

  • 00000000b..=00111111b (0..=63 inclusive): Simple account/address/network identifier. The byte can be interpreted directly as such an identifier.
  • 01000000b..=01111111b (64..=127 inclusive): Full address/address/network identifier. The lower 6 bits of this byte should be treated as the upper 6 bits of a 14 bit identifier value, with the lower 8 bits defined by the following byte. This works for all identifiers up to 2**14 (16,383).
  • 10000000b..=11111111b (128..=255 inclusive): Reserved for future address format extensions.

The latter (42) is a "wildcard" address that is meant to be equally valid on all Substrate networks that support fixed-length addresses. For production networks, however, a network-specific version may be desirable to help avoid the key-reuse between networks and some of the problems that it can cause. Substrate nodes will default to printing keys in address type 42, though alternative Substrate-based node implementations (e.g. Polkadot) may elect to default to some other type.

Address Formats for Substrate

There are 16 different address formats, identified by the length (in bytes) of the total payload (i.e. including the checksum).

TotalTypeRaw AccountChecksum
3111
4121
5122
6141
7142
8143
9144
10181
11182
12183
13184
14185
15186
16187
17188
351322

Checksum types

Several potential checksum strategies exist within Substrate, giving different length and longevity guarantees. There are two types of checksum preimages (known as SS58 and AccountID) and many different checksum lengths (1 to 8 bytes).

In all cases for Substrate, the Blake2b-512 (Spec, Wiki) hash function is used (OID 1.3.6.1.4.1.1722.12.2.1.16). The variants simply select the preimage used as the input to the hash function and the number of bytes taken from its output.

The bytes used are always the left most bytes. The input to be used is the non-checksum portion of the SS58 byte series used as input to the base-58 function, i.e. concat( <address-type>, <address> ). A context prefix of 0x53533538505245, (the string SS58PRE) is prepended to the input to give the final hashing preimage.

The advantage of using more checksum bytes is simply that more bytes provide a greater degree of protection against input errors and index alteration at the cost of widening the textual address by an extra few characters. For the account ID format, this is insignificant and therefore no 1-byte alternative is provided. For the shorter account-index formats, the extra byte represents a far greater portion of the final address, so it is left for further up the stack (though not necessarily the user themselves) to determine the best tradeoff for their purposes.

Simple/full address types and account/address/network identifiers

The registry expresses the status of the account/address/network identifiers.

Identifiers up to value 64 may be expressed in a simple format address, in which the least significant byte (LSB) of the identifier value is expressed as the first byte of the encoded address.

For identifiers of between 64 and 16,383, the full format address must be used.

This encoding is slightly fiddly since we encode as little endian (LE), yet the first two bits (which should encode 64s and 128s) are already used up with the necessary 01 prefix. We treat the first two bytes as a 16 bit sequence, and we disregard the first two bits of that (since they're already fixed to be 01). With the remaining 14 bits, we encode our identifier value as LE, with the assumption that the two missing higher order bits are zero. This effectively spreads the low-order byte across the boundary between the two bytes.

Thus the 14-bit identifier 0b00HHHHHH_MMLLLLLL is expressed in the two bytes as:

  • 0b01LLLLLL
  • 0bHHHHHHMM

Identifiers of 16384 and beyond are not currently supported.

Validating addresses

There are several ways to verify that a value is a valid SS58 address.

Subkey

You can use the Subkey inspect subcommand, which accepts the seed phrase, a hex-encoded private key, or an SS58 address as the input URI. If the input is a valid address, it will return a list containing the corresponding public key (hex), account ID and SS58 values.

Subkey assumes that an address is based on a public/private keypair. In the case of inspecting an address, it will return the 32 byte account ID. Not all addresses in Substrate-based networks are based on keys.

Note

If you input a valid SS58 value, Subkey will also return a network ID/version value that indicates for which network the address has been encoded.

# A valid address.
$ subkey inspect "12bzRJfh7arnnfPPUZHeJUaE62QLEwhK48QnH9LXeK2m1iZU"
Public Key URI `12bzRJfh7arnnfPPUZHeJUaE62QLEwhK48QnH9LXeK2m1iZU` is account:
  Network ID/version: polkadot
  Public key (hex):   0x46ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a
  Account ID:         0x46ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a
  SS58 Address:       12bzRJfh7arnnfPPUZHeJUaE62QLEwhK48QnH9LXeK2m1iZU

# An invalid address.
$ subkey inspect "12bzRJfh7arnnfPPUZHeJUaE62QLEwhK48QnH9LXeK2m1iZUInvalidAddress"
Invalid phrase/URI given

PolkadotJS API

For verifying an address in your JavaScript projects, you can utilize the functions built into the PolkadotJS API.

// Import Polkadot.js API dependencies.
const { decodeAddress, encodeAddress } = require('@polkadot/keyring')
const { hexToU8a, isHex } = require('@polkadot/util')

// Specify an address to test.
const address = '<addressToTest>'

// Check address.
const isValidSubstrateAddress = () => {
  try {
    encodeAddress(isHex(address) ? hexToU8a(address) : decodeAddress(address))

    return true
  } catch (error) {
    return false
  }
}

// Query result.
const isValid = isValidSubstrateAddress()
console.log(isValid)

Learn more

Last edit: on

Run into problems?
Let us Know