18 - Dash Platform Payment Address Encodings#
DIP: 0018 Title: Dash Platform Payment Address Encodings Author(s): Samuel Westrich, thephez Special-Thanks: Dash Platform Team Comments-Summary: No comments yet. Status: Proposed Type: Standard Created: 2025-11-28 License: MIT License Replaces: - Superseded-By: -
Table of Contents#
Abstract#
This DIP specifies the bech32m address encoding formats for Dash Platform payments. It defines the human-readable part (HRP), data layout, and checksum rules for Platform pay-to-public-key-hash (P2PKH) addresses derived via DIP-17, and introduces Platform pay-to-script-hash (P2SH) addresses. Distinct HRPs for Platform prevent confusion with Dash Core chain addresses and with other bech32-based formats.
Motivation#
Platform payment keys are derived under DIP-17. To interoperate between wallets, hardware wallets, and services, a standard encoding with explicit network separation is required. This DIP adopts bech32m, which provides strong error detection, produces compact QR codes, and excludes ambiguous characters.
Prior Work#
Specification#
Address Types#
Platform P2PKH:
HASH160(pubkey)wherepubkeyis a compressed secp256k1 public key derived per DIP-17.Platform P2SH:
HASH160(script)wherescriptis the raw byte serialization of a Platform script (e.g., multisig or policy script) being paid to.
Encoding#
Encoding Algorithm Summary#
Encoding a Dash Platform address uses the bech32m format defined in BIP-350, with the general encoding rules inherited from BIP-173.
Given:
hrp: the network human-readable prefix (e.g.,dash,tdash)type_byte:0xb0for P2PKH or0x80for P2SHhash160: a 20-byteHASH160(pubkey or script)value
The address MUST be encoded as follows:
Form the 21-byte payload:
payload = type_byte || hash160Convert the payload from 8-bit bytes to 5-bit groups using the standard
convertbits()procedure described in BIP-173, with padding enabledCompute the bech32m checksum using the algorithm defined in BIP-350, including HRP expansion and polymod evaluation using the bech32 generator constants
Append the checksum to the data and map the resulting 5-bit values to characters using the bech32 alphabet defined in BIP-173 (
qpzry9x8gf2tvdw0s3jn54khce6mua7l)Produce the final address string:
hrp + "1" + encoded_data
Decoders MUST reverse these steps and MUST verify:
Checksum validity (per BIP-350),
HRP correctness for the target network,
Data-part length requirements,
The type byte is either
0xb0or0x80.
Structure#
All Platform addresses are encoded as:
<HRP> "1" <data-part>
<HRP>is network-specific (see table).<data-part>contains:one type byte (
0xb0P2PKH,0x80P2SH), followed by20-byte HASH160 payload encoded as 5-bit groups via bech32 rules.
The checksum MUST be calculated using the bech32m algorithm as defined in BIP-350.
Rules#
MUST be lowercase when encoded and displayed.
Decoders MUST reject mixed-case input.
Uppercase MAY be accepted but MUST normalize to lowercase before storage/display.
Attempting to validate or decode Dash Platform addresses using legacy bech32 rules (BIP-173 checksum constant) MUST fail.
Character set#
The bech32m encoding used in this specification requires a fixed, 32-character base-32 alphabet. The data portion of all encoded addresses MUST use the same character set as Bitcoin:
qpzry9x8gf2tvdw0s3jn54khce6mua7l
Network Parameters#
The following values define the canonical human-readable prefixes (HRPs) and type-byte assignments for Dash Platform addresses. These values are fixed and MUST be used exactly as specified.
Network |
HRP |
|---|---|
Mainnet |
|
Testnet / Devnet / Regtest |
|
Type byte meaning:
Address Type |
Type byte |
First data character |
|---|---|---|
Platform P2PKH |
|
|
Platform P2SH |
|
|
The type bytes 0xb0 and 0x80 were specifically chosen so that the first character after the 1 separator is always k for P2PKH and s for P2SH. This provides immediate visual identification of address type:
P2PKH addresses always match pattern
dash1k...(mainnet) ortdash1k...(testnet)P2SH addresses always match pattern
dash1s...(mainnet) ortdash1s...(testnet)
This mapping is guaranteed because the bech32 convertbits() function deterministically converts the first 5 bits of the type byte to the first data character. The high 5 bits of 0xb0 (binary 10110...) map to index 22 in the bech32 alphabet (k), while the high 5 bits of 0x80 (binary 10000...) map to index 16 (s).
Reserved Type Byte Ranges#
To preserve visual identification, future address types MUST NOT reuse the first-character mappings of existing types. The first data character is determined by the high 5 bits of the type byte:
High 5 bits |
First char |
Reserved for |
Type byte range |
|---|---|---|---|
|
|
P2PKH |
|
|
|
P2SH |
|
Future address types SHOULD select type bytes that produce unique first characters not already in use. The reference script dip-0018/type_byte_calc.py can be used to find type bytes that map to a desired character.
Validation#
A Platform address is valid if:
It is lowercase or uppercase (but not mixed).
HRP matches expected network.
bech32m checksum verifies.
Payload decodes to exactly 21 bytes.
payload[0]is0xb0or0x80.
Wallets MUST reject Platform addresses when constructing Core chain scripts and SHOULD present a clear warning if a user attempts to mix layers.
Wallet and Hardware Wallet Behavior#
Wallets MUST use the P2PKH encoding above for public keys derived per DIP-17.
Wallets MUST use the P2SH encoding for Platform scripts intended to receive Platform funds.
Wallets MUST treat HRP as the network selector.
Software wallets SHOULD label Platform balances separately from Core chain balances and SHOULD avoid auto-pasting Platform addresses into Core chain contexts.
Wallets SHOULD derive payloads via DIP-17 and then encode using these rules; no alternative prefixes are allowed.
Hardware wallets MUST validate the HRP to confirm network identity and MUST enforce the type byte (
0xb0or0x80). Devices MUST display a user-facing descriptor: “Dash Platform address” for P2PKH and “Dash Platform script address” for P2SH.
Rationale#
Why Bech32m?#
Bech32m was chosen over Base58Check because it:
Improves checksum strength
Is QR efficient
Avoids ambiguous characters
Clearly separates networks using HRPs
Future-proofs script or address extensions
Why a Type Byte?#
Platform addresses embed a type byte as the first byte of the payload. This approach was chosen because:
Platform addresses distinguish between address types (P2PKH vs P2SH) for wallet display purposes, not script interpretation versions for consensus (e.g., P2WPKH/P2WSH vs Taproot in Bitcoin). Both address types use identical HASH160 payloads with the same cryptographic properties.
A full byte in the payload is straightforward to encode and decode without special handling separate from the hash data.
Specific type byte values improve human identification of address type by guaranteeing that P2PKH and P2SH addresses have a unique starting characters.
Note: The type byte values defined here (0xb0, 0x80) are specific to the bech32m address encoding. Platform implementations use compact variant indices (e.g., 0x00 for P2PKH, 0x01 for P2SH) for internal storage and database keys. Implementations MUST map between these representations when encoding or decoding addresses.
Backwards Compatibility#
No impact on Core chain addresses. Platform P2PKH/P2SH prefixes are new and cannot be misinterpreted as existing Dash formats. Seeds and derivation (DIP-17) are unchanged.
Reference Implementation#
Note: The following pseudocode covers the encoding and decoding parts of DIP-18 only, not the wallet-UI or signing device behaviors.
function encode_platform_address(hash160, type, network):
# type: "p2pkh" or "p2sh"
# network: "mainnet" or "testnet"
if len(hash160) != 20:
error("invalid hash160 length")
type_byte = 0xb0 if type=="p2pkh" else 0x80 if type=="p2sh" else error()
hrp = {
"mainnet": "dash",
"testnet": "tdash",
}.get(network) or error()
payload = [type_byte] || hash160
data = convertbits(payload, 8, 5, pad=true)
return bech32m_encode(hrp, data)
function decode_platform_address(addr):
if mixed_case(addr): error("mixed case not allowed")
addr = to_lowercase(addr)
# bech32m_decode MUST:
# - verify bech32m checksum (BIP-350)
# - validate character set
# - return (hrp, data_without_checksum)
hrp, data = bech32m_decode(addr)
# Infer network from HRP
network = {
"dash": "mainnet",
"tdash": "testnet",
}.get(hrp)
if network is null:
error("unknown hrp / network")
payload = convertbits(data, 5, 8, pad=false)
if payload is null:
error("invalid payload encoding")
if len(payload) != 21:
error("invalid payload length")
type_byte = payload[0]
hash160 = payload[1:21]
if type_byte == 0xb0:
addr_type = "p2pkh"
else if type_byte == 0x80:
addr_type = "p2sh"
else:
error("unknown type byte")
return network, addr_type, hash160
A Python implementation is available at dip-0018/bech32.py. It uses the BIP-350 reference code by Pieter Wuille and validates against the provided test vectors.
Security Considerations#
Checksums detect mistyped addresses; distinct prefixes reduce layer-mixing mistakes.
Hardware wallet whitelisting of prefixes mitigates key-path confusion.
P2SH scripts must be fully validated by wallets before signing or displaying to prevent malicious script substitution.
Privacy Considerations#
Privacy relies on HD key rotation per DIP-17 and script hygiene.
P2SH script hashes reveal neither full script nor participant keys but can still be correlated if reused; wallets SHOULD discourage P2SH reuse.
Test Vectors#
Mnemonic (shared with DIP-17): abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
Passphrase: ""
The HASH160 payloads in the following tables are derived from the mnemonic and paths specified in DIP-17. Implementations MAY use those derivation vectors to perform end-to-end tests (mnemonic → key → pubkey → HASH160 → address).
P2PKH examples#
Vector |
Payload (HASH160) |
Mainnet ( |
Testnet ( |
|---|---|---|---|
1 |
|
|
|
2 |
|
|
|
3 |
|
|
|
P2SH example#
Payload: 43fa183cf3fb6e9e7dc62b692aeb4fc8d8045636
Mainnet:
dash1sppl5xpu70aka8nacc4kj2htflydspzkxch4cad6Testnet:
tdash1sppl5xpu70aka8nacc4kj2htflydspzkxc8jtru5
Copyright#
Copyright (c) 2025 Dash Core Group, Inc. Licensed under the MIT License