## Preamble
```
SEP: 0023
Title: Strkeys
Author: David Mazières, Tomer Weller <@tomerweller>, Leigh McCulloch <@leighmcculloch>, Alfonso Acosta <@2opremio>
Status: Active
Created: 2019-09-16
Updated: 2026-09-18
Version: 1.4.0
Discussion: https://groups.google.com/g/stellar-dev
```
## Simple Summary
Strkey is an ASCII format for representing Stellar account IDs and addresses.
## Motivation
A canonical representation for encoding Stellar account IDs, muxed accounts,
and other signers of Stellar transactions and accounts improves
interoperability. Applications in the Stellar ecosystem may refer to an
account, a muxed account, or a signer, using a common format and therefore
understand each other. Strkeys are used widely in other SEPs.
## Abstract
Strkey is an ASCII encoding for Stellar account IDs, muxed accounts, and
signers. Applications may reliably encode or decode a Strkey with each account
having a single valid representation.
## Specification
Strkey, the ASCII encoding for accounts, keys, and signers, currently covers
ED25519 public keys, ED25519 private keys (also known as seeds), pre-authorized
transaction hashes, and hash-x signers (which provide signing authority upon
revelation of a SHA-256 preimage), muxed accounts (introduced in [CAP-27]),
signed payload signers (introduced in [CAP-40]), contracts, liquidity pools,
claimable balances, and muxed contracts (introduced in [CAP-84]).
Each strkey has its type encoded in the top 5 bits of the version byte, which
is the first 8 bits of the strkey. The possible "base" values (top 5 bits) of
the version byte, which determine the first character of the base-32 encoding
of the key, are listed here:
| Key type | Base value | First char | Muxed | Alg |
| ------------------------ | ---------- | ---------- | ----- | ---- |
| STRKEY_PUBKEY | 6 << 3 | G | no | PK |
| STRKEY_MUXED | 12 << 3 | M | yes | PK |
| STRKEY_PRIVKEY | 18 << 3 | S | no | PK |
| STRKEY_PRE_AUTH_TX | 19 << 3 | T | no | Hash |
| STRKEY_HASH_X | 23 << 3 | X | no | Hash |
| STRKEY_SIGNED_PAYLOAD | 15 << 3 | P | no | PK |
| STRKEY_CONTRACT | 2 << 3 | C | no | Hash |
| STRKEY_LIQUIDITY_POOL | 11 << 3 | L | no | Hash |
| STRKEY_CLAIMABLE_BALANCE | 1 << 3 | B | no | Hash |
| STRKEY_MUXED_CONTRACT | 22 << 3 | W | yes | Hash |
The low 3 bits of the version byte encode an algorithm specifier. Thus, a
version byte becomes the bitwise OR of a base value above and one of the
algorithm specifiers from the two tables below. (These tables will be extended
when Stellar adds additional crypto algorithms.)
| PK Algorithm | Value |
| ------------------ | ----- |
| STRKEY_ALG_ED25519 | 0 |
| Hash Algorithm | Value |
| ----------------- | ----- |
| STRKEY_ALG_SHA256 | 0 |
The following steps transform a binary key into a strkey:
1. Start with the appropriate version byte computed by the OR of a key type
base value and algorithm selector from the tables above.
2. Append the binary bytes of the key (e.g., 32-bytes for ED25519, 32-bytes
for SHA256).
If we are encoding a claimable balance, the binary bytes of the key has a
length of 33-bytes: 1-byte value indicating the type of claimable balance,
where 0x00 maps to V0, and a 32-byte SHA256 hash.
3. If we are encoding a multiplexed address (a muxed account or a muxed
contract), append an 8-byte ID in network byte order (most significant byte
first).
4. If we are encoding a signed payload, append a 4-byte length in network byte
order (most significant byte first) that holds the length of the payload,
then append the payload, and finally zero padding of 0 to 3 zero bytes such
that the total number of bytes of the payload plus the zero padding is a
multiple of four.
5. Compute a 16-bit CRC16 checksum of the result of the prior step (using
polynomial x16 + x12 + x5 \+ 1). Append
the two-byte checksum to the result of the previous step (e.g., producing a
35-byte quantity for a non-multiplexed ED25519 public key, or 43 byte
quantity for a multiplexed one).
6. Encode the result of the previous step using
[RFC4648 base-32 encoding](https://tools.ietf.org/html/rfc4648#section-6)
without padding. For example, a multiplexed address yields a 43-byte
quantity whose base-32 encoding is 69 bytes with no trailing `=` signs
because no padding is allowed.
To transform a strkey into a binary key, the process is simply reversed.
However, a strkey is only valid if re-encoding the binary key yields the exact
same strkey. Note, in particular, that a strkey's length **must not** be
congruent to 1, 3, or 6 mod 8, and unused bits of the last symbol must be zero.
Some non-padding base32 libraries, such as the one in the standard go
library—`base32.StdEncoding.WithPadding(base32.NoPadding)`—do not
enforce these requirements. Therefore, implementations of strkey decoding
**must** check and reject such invalid inputs, or perform a round-trip and
reject strkey inputs that do not re-encode to the exact same string.
The CRC is an error detection mechanism but does not guarantee that a strkey
has not been truncated. Existing strkeys have a determinible length based on
their strkey type and algorithmn specifier.
## Tests
Implementations of strkey must accept the following valid test cases and reject
the invalid test cases. Common bugs such as forgetting to reject strkeys with
length congruent to 1, 3, or 6 mod 8 before invoking base-32 decoding will
cause software to accept the invalid test cases, which could in turn cause
security problems.
### Valid test cases
1. Valid non-multiplexed account
- Strkey `GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ`
- type: `KEY_TYPE_ED25519`
- Binary `MuxedAccount`:
```{.c}
{
0x00, 0x00, 0x00, 0x00, 0x3f, 0x0c, 0x34, 0xbf,
0x93, 0xad, 0x0d, 0x99, 0x71, 0xd0, 0x4c, 0xcc,
0x90, 0xf7, 0x05, 0x51, 0x1c, 0x83, 0x8a, 0xad,
0x97, 0x34, 0xa4, 0xa2, 0xfb, 0x0d, 0x7a, 0x03,
0xfc, 0x7f, 0xe8, 0x9a,
}
```
1. Valid multiplexed account
- Strkey:
`MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAACJUQ`
- type: `KEY_TYPE_MUXED_ED25519`
- id: 0
- ed25519: `GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ`
- Binary `MuxedAccount`:
```{.c}
{
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3f, 0x0c, 0x34, 0xbf,
0x93, 0xad, 0x0d, 0x99, 0x71, 0xd0, 0x4c, 0xcc,
0x90, 0xf7, 0x05, 0x51, 0x1c, 0x83, 0x8a, 0xad,
0x97, 0x34, 0xa4, 0xa2, 0xfb, 0x0d, 0x7a, 0x03,
0xfc, 0x7f, 0xe8, 0x9a,
}
```
1. Valid multiplexed account in which unsigned id exceeds maximum signed 64-bit
integer
- Strkey:
`MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVAAAAAAAAAAAAAJLK`
- type: `KEY_TYPE_MUXED_ED25519`
- id: 9223372036854775808
- ed25519: `GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ`
- Binary `MuxedAccount`:
```{.c}
{
0x00, 0x00, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3f, 0x0c, 0x34, 0xbf,
0x93, 0xad, 0x0d, 0x99, 0x71, 0xd0, 0x4c, 0xcc,
0x90, 0xf7, 0x05, 0x51, 0x1c, 0x83, 0x8a, 0xad,
0x97, 0x34, 0xa4, 0xa2, 0xfb, 0x0d, 0x7a, 0x03,
0xfc, 0x7f, 0xe8, 0x9a,
}
```
1. Valid signed payload with an ed25519 public key and a 32-byte payload.
- Strkey:
`PA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAQACAQDAQCQMBYIBEFAWDANBYHRAEISCMKBKFQXDAMRUGY4DUPB6IBZGM`
- type: `KEY_TYPE_ED25519_SIGNED_PAYLOAD`
- ed25519: `GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ`
- payload: 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20
(hex)
1. Valid signed payload with an ed25519 public key and a 29-byte payload which
becomes zero padded.
- Strkey:
`PA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAOQCAQDAQCQMBYIBEFAWDANBYHRAEISCMKBKFQXDAMRUGY4DUAAAAFGBU`
- type: `KEY_TYPE_ED25519_SIGNED_PAYLOAD`
- ed25519: `GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ`
- payload: 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d (hex)
1. Valid contract
- Strkey `CA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUWDA`
- type: `HASH_TYPE_SHA256`
- hash:
```{.c}
{
0x3f, 0x0c, 0x34, 0xbf, 0x93, 0xad, 0x0d, 0x99,
0x71, 0xd0, 0x4c, 0xcc, 0x90, 0xf7, 0x05, 0x51,
0x1c, 0x83, 0x8a, 0xad, 0x97, 0x34, 0xa4, 0xa2,
0xfb, 0x0d, 0x7a, 0x03, 0xfc, 0x7f, 0xe8, 0x9a,
}
```
1. Valid liquidity pool address
- Strkey `LA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUPJN`
- type: `HASH_TYPE_SHA256`
- hash:
```{.c}
{
0x3f, 0x0c, 0x34, 0xbf, 0x93, 0xad, 0x0d, 0x99,
0x71, 0xd0, 0x4c, 0xcc, 0x90, 0xf7, 0x05, 0x51,
0x1c, 0x83, 0x8a, 0xad, 0x97, 0x34, 0xa4, 0xa2,
0xfb, 0x0d, 0x7a, 0x03, 0xfc, 0x7f, 0xe8, 0x9a,
}
```
1. Valid claimable balance address
- Strkey `BAAD6DBUX6J22DMZOHIEZTEQ64CVCHEDRKWZONFEUL5Q26QD7R76RGR4TU`
- type: `HASH_TYPE_SHA256`
- claimable balance type: `v0`
- hash:
```{.c}
{
0x3f, 0x0c, 0x34, 0xbf, 0x93, 0xad, 0x0d, 0x99,
0x71, 0xd0, 0x4c, 0xcc, 0x90, 0xf7, 0x05, 0x51,
0x1c, 0x83, 0x8a, 0xad, 0x97, 0x34, 0xa4, 0xa2,
0xfb, 0x0d, 0x7a, 0x03, 0xfc, 0x7f, 0xe8, 0x9a,
}
```
1. Valid muxed contract address
- Strkey:
`WA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAAAWWC`
- type: `SC_ADDRESS_TYPE_MUXED_CONTRACT`
- id: 0
- contract: `CA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUWDA`
- hash:
```{.c}
{
0x3f, 0x0c, 0x34, 0xbf, 0x93, 0xad, 0x0d, 0x99,
0x71, 0xd0, 0x4c, 0xcc, 0x90, 0xf7, 0x05, 0x51,
0x1c, 0x83, 0x8a, 0xad, 0x97, 0x34, 0xa4, 0xa2,
0xfb, 0x0d, 0x7a, 0x03, 0xfc, 0x7f, 0xe8, 0x9a,
}
```
1. Valid muxed contract address in which unsigned id exceeds maximum signed
64-bit integer
- Strkey:
`WA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVAAAAAAAAAAAACWJY`
- type: `SC_ADDRESS_TYPE_MUXED_CONTRACT`
- id: 9223372036854775808
- contract: `CA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUWDA`
- hash:
```{.c}
{
0x3f, 0x0c, 0x34, 0xbf, 0x93, 0xad, 0x0d, 0x99,
0x71, 0xd0, 0x4c, 0xcc, 0x90, 0xf7, 0x05, 0x51,
0x1c, 0x83, 0x8a, 0xad, 0x97, 0x34, 0xa4, 0xa2,
0xfb, 0x0d, 0x7a, 0x03, 0xfc, 0x7f, 0xe8, 0x9a,
}
```
### Invalid test cases
1. Invalid length (Ed25519 should be 32 bytes, not 5)
- Strkey: `GAAAAAAAACGC6`
1. The unused trailing bit must be zero in the encoding of the last three bytes
(24 bits) as five base-32 symbols (25 bits)
- Strkey:
`MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAACJUR`
1. Invalid length (congruent to 1 mod 8)
- Strkey: `GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZA`
1. Invalid length (base-32 decoding should yield 35 bytes, not 36)
- Strkey: `GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUACUSI`
1. Invalid algorithm (low 3 bits of version byte are 7)
- Strkey: `G47QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVP2I`
1. Invalid length (congruent to 6 mod 8)
- Strkey:
`MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVAAAAAAAAAAAAAJLKA`
1. Invalid length (base-32 decoding should yield 43 bytes, not 44)
- Strkey:
`MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVAAAAAAAAAAAAAAV75I`
1. Invalid algorithm (low 3 bits of version byte are 7)
- Strkey:
`M47QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAACJUQ`
1. Padding bytes are not allowed
- Strkey:
`MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAACJUK===`
1. Invalid checksum
- Strkey:
`MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAACJUO`
1. Length prefix specifies length that is shorter than payload in signed
payload
- Strkey:
`PA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAQACAQDAQCQMBYIBEFAWDANBYHRAEISCMKBKFQXDAMRUGY4DUPB6IAAAAAAAAPM`
1. Length prefix specifies length that is longer than payload in signed payload
- Strkey:
`PA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAOQCAQDAQCQMBYIBEFAWDANBYHRAEISCMKBKFQXDAMRUGY4Z2PQ`
1. No zero padding in signed payload
- Strkey:
`PA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAOQCAQDAQCQMBYIBEFAWDANBYHRAEISCMKBKFQXDAMRUGY4DXFH6`
1. The unused trailing 2-bits must be zero in the encoding of the last symbol.
- Strkey: `BAAD6DBUX6J22DMZOHIEZTEQ64CVCHEDRKWZONFEUL5Q26QD7R76RGR4TV`
1. Invalid claimable balance type (first byte of binary key is not 0)
- Strkey: `BAAT6DBUX6J22DMZOHIEZTEQ64CVCHEDRKWZONFEUL5Q26QD7R76RGXACA`
1. The unused trailing bit must be zero in the encoding of the last three bytes
(24 bits) as five base-32 symbols (25 bits) of a muxed contract
- Strkey:
`WA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAAAWWD`
1. Invalid length (congruent to 6 mod 8) of a muxed contract
- Strkey:
`WA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAAAWWCA`
1. Invalid length (base-32 decoding should yield 43 bytes, not 44) of a muxed
contract
- Strkey:
`WA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAAAAIOUI`
1. Invalid algorithm (low 3 bits of version byte are 7) of a muxed contract
- Strkey:
`W47QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAADXHW`
1. Invalid checksum of a muxed contract
- Strkey:
`WA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAAAWWA`
You can paste these invalid strkeys more conveniently into a unit test using
the following array:
```{.c}
{
"GAAAAAAAACGC6",
"MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAACJUR",
"GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZA",
"GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUACUSI",
"G47QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVP2I",
"MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVAAAAAAAAAAAAAJLKA",
"MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVAAAAAAAAAAAAAAV75I",
"M47QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAACJUQ",
"MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAACJUK===",
"MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAACJUO",
"PA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAQACAQDAQCQMBYIBEFAWDANBYHRAEISCMKBKFQXDAMRUGY4DUPB6IAAAAAAAAPM",
"PA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAOQCAQDAQCQMBYIBEFAWDANBYHRAEISCMKBKFQXDAMRUGY4Z2PQ",
"PA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAOQCAQDAQCQMBYIBEFAWDANBYHRAEISCMKBKFQXDAMRUGY4DXFH6",
"BAAD6DBUX6J22DMZOHIEZTEQ64CVCHEDRKWZONFEUL5Q26QD7R76RGR4TV",
"BAAT6DBUX6J22DMZOHIEZTEQ64CVCHEDRKWZONFEUL5Q26QD7R76RGXACA",
"WA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAAAWWD",
"WA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAAAWWCA",
"WA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAAAAIOUI",
"W47QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAADXHW",
"WA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAAAWWA",
}
```
## Implementation
There are many implementations of strkey in Stellar SDKs. As a reference, the
following implementations are kept up-to-date with this SEP.
https://github.com/xdrpp/stc
https://github.com/stellar/rs-stellar-strkey
## Security Concerns
None.
[CAP-27]: ../core/cap-0027.md
[CAP-40]: ../core/cap-0040.md
[CAP-84]: ../core/cap-0084.md