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#

  1. Abstract

  2. Motivation

  3. Prior Work

  4. Specification

    1. Address Types

    2. Encoding

    3. Network Parameters

    4. Validation

    5. Wallet and Hardware Wallet Behavior

  5. Rationale

  6. Backwards Compatibility

  7. Reference Implementation

  8. Security Considerations

  9. Privacy Considerations

  10. Test Vectors

  11. Copyright

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) where pubkey is a compressed secp256k1 public key derived per DIP-17.

  • Platform P2SH: HASH160(script) where script is 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: 0xb0 for P2PKH or 0x80 for P2SH

  • hash160: a 20-byte HASH160(pubkey or script) value

The address MUST be encoded as follows:

  1. Form the 21-byte payload: payload = type_byte || hash160

  2. Convert the payload from 8-bit bytes to 5-bit groups using the standard convertbits() procedure described in BIP-173, with padding enabled

  3. Compute the bech32m checksum using the algorithm defined in BIP-350, including HRP expansion and polymod evaluation using the bech32 generator constants

  4. Append the checksum to the data and map the resulting 5-bit values to characters using the bech32 alphabet defined in BIP-173 (qpzry9x8gf2tvdw0s3jn54khce6mua7l)

  5. 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 0xb0 or 0x80.

Structure#

All Platform addresses are encoded as:

<HRP> "1" <data-part>
  • <HRP> is network-specific (see table).

  • <data-part> contains:

    • one type byte (0xb0 P2PKH, 0x80 P2SH), followed by

    • 20-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

dash

Testnet / Devnet / Regtest

tdash

Type byte meaning:

Address Type

Type byte

First data character

Platform P2PKH

0xb0

k

Platform P2SH

0x80

s

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) or tdash1k... (testnet)

  • P2SH addresses always match pattern dash1s... (mainnet) or tdash1s... (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

10110

k

P2PKH

0xb00xb7

10000

s

P2SH

0x800x87

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:

  1. It is lowercase or uppercase (but not mixed).

  2. HRP matches expected network.

  3. bech32m checksum verifies.

  4. Payload decodes to exactly 21 bytes.

  5. payload[0] is 0xb0 or 0x80.

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 (0xb0 or 0x80). 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 (dash)

Testnet (tdash)

1

f7da0a2b5cbd4ff6bb2c4d89b67d2f3ffeec0525

dash1krma5z3ttj75la4m93xcndna9ullamq9y5e9n5rs

tdash1krma5z3ttj75la4m93xcndna9ullamq9y5fzq2j7

2

a5ff0046217fd1c7d238e3e146cc5bfd90832a7e

dash1kzjl7qzxy9lar37j8r37z3kvt07epqe20ckxfezw

tdash1kzjl7qzxy9lar37j8r37z3kvt07epqe20cxp68nq

3

6d92674fd64472a3dfcfc3ebcfed7382bf699d7b

dash1kpkeye606ez89g7lelp7hnldwwpt76va0v3j6x28

tdash1kpkeye606ez89g7lelp7hnldwwpt76va0vp4fcmf

P2SH example#

Payload: 43fa183cf3fb6e9e7dc62b692aeb4fc8d8045636

  • Mainnet: dash1sppl5xpu70aka8nacc4kj2htflydspzkxch4cad6

  • Testnet: tdash1sppl5xpu70aka8nacc4kj2htflydspzkxc8jtru5