From 5921f5bb1f62bebbfd7501522ef3177f22657e43 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Fri, 28 Nov 2025 17:45:23 +0700 Subject: [PATCH 1/7] Add DIP-17 derivation for Platform payments and DIP-18 encoding (P2PKH/P2SH) with Core vs Platform terminology --- dip-0009/assignments.md | 1 + dip-0017.md | 170 ++++++++++++++++++++++++++++++++++++++++ dip-0018.md | 168 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 339 insertions(+) create mode 100644 dip-0017.md create mode 100644 dip-0018.md diff --git a/dip-0009/assignments.md b/dip-0009/assignments.md index d0f6adaf..7e7e137a 100644 --- a/dip-0009/assignments.md +++ b/dip-0009/assignments.md @@ -9,6 +9,7 @@ Here is a table of current feature paths and any associated DIP. Future DIPs may | `5'` | Identity Keys | [DIP 0013: Identities in Hierarchical Deterministic wallets](../dip-0013.md) | The related keys are located in the following sub-paths:
`0'/key type'/identity index'/key index'/*` - Identity Authentication ([details](../dip-0013.md#identity-authentication-keys))
`1'/*` - Identity Registration Funding ([details](../dip-0013.md#identity-registration-funding-keys))
`2'/*` - Identity Topup Funding ([details](../dip-0013.md#identity-top-up-funding-keys))
`3'/*` - Identity Invitation Funding ([details](../dip-0013.md#identity-invitatation-funding-keys))

For example, the first Identity Registration Funding key for Dash would be at `m/9'/5'/5'/1'/0` | | `15'` | DashPay - Incoming Funds | [DIP 0015: DashPay](../dip-0015.md#dashpay-incoming-funds-derivation-path) | The related keys are located in the following sub-paths: `/0'/account'/*`

For example, incoming funds for the first identity would be at `m/9'/5'/15'/0'/*` | | `16'` | DashPay - Auto Accept Proof | [DIP 0015: DashPay](../dip-0015.md#auto-accept-proof-autoacceptproof) | The related keys are located in the following sub-paths: `16'/expiration timestamp'`

For example, the key for a proof expiring at a Unix epoch time of `1605927033` would be at `m/9'/5'/16'/1605927033'` | +| `17'` | Platform Payment Addresses | [DIP 0017: Dash Platform Payment Addresses and HD Derivation](../dip-0017.md) | The related keys are located in the following sub-paths: `17'/key_class'/index` (default key_class' = `0'`) | Note: all DIP 0009 paths are of the format: `m / 9' / coin_type' / feature' / *` diff --git a/dip-0017.md b/dip-0017.md new file mode 100644 index 00000000..b2e04936 --- /dev/null +++ b/dip-0017.md @@ -0,0 +1,170 @@ +
+  DIP: 0017
+  Title: Dash Platform Payment Addresses and HD Derivation
+  Author(s): Samuel Westrich
+  Special-Thanks: Dash Platform Team
+  Comments-Summary: No comments yet.
+  Status: Draft
+  Type: Standard
+  Created: 2024-05-23
+  License: MIT License
+  Replaces: -
+  Superseded-By: -
+
+ +## Table of Contents + +1. [Abstract](#abstract) +1. [Motivation](#motivation) +1. [Specification](#specification) + 1. [Overview](#overview) + 1. [Derivation Path Definition](#derivation-path-definition) + 1. [Wallet and Hardware Wallet Behavior](#wallet-and-hardware-wallet-behavior) +1. [Rationale](#rationale) +1. [Backwards Compatibility](#backwards-compatibility) +1. [Reference Implementation](#reference-implementation) +1. [Security Considerations](#security-considerations) +1. [Privacy Considerations](#privacy-considerations) +1. [Test Vectors](#test-vectors) +1. [DIP-9 Registry Update](#dip-9-registry-update) +1. [Copyright](#copyright) + +# Abstract + +This DIP defines Dash Platform payment addresses (“D-addresses”) and their hierarchical deterministic (HD) derivation under DIP-9. It uses Dash coin type 5' on mainnet and coin type 1' on test networks, and introduces a new DIP-9 feature index for Platform payments. The specification standardizes derivation paths (including account separation) and wallet/hardware wallet guidance for Platform payment keys. Address encoding (version bytes and formats) and script-hash address formats are defined in DIP-0018. + +# Motivation + +Dash Platform enables value transfers distinct from Dash Core chain (L1) UTXO transactions. Wallets require an unambiguous address type, network-specific encodings, and deterministic derivation paths that coexist with BIP-44 Core chain funds and existing DIP-9 features (masternodes, identities, DashPay). This DIP provides a single standard so wallets, hardware wallets, and services can implement Platform payments without changing seeds or coin types. + +# Specification + +## Overview + +Platform payment keys identify recipients of Platform-level value—specifically Dash Credits (DCredits), the form of Dash held on the Platform chain—and may also be used for other Platform payments. They are derived from a single secp256k1 key pair, not from scripts. They are not valid Dash Core chain addresses and SHOULD NOT be used in Core chain transactions. Address encoding for these keys is specified in DIP-0018. + +## Derivation Path Definition + +The Platform payment feature is assigned DIP-9 feature index `17'`. The canonical derivation path is: + +``` +m / 9' / coin_type' / 17' / account' / key_class' / index +``` + +Normative requirements: + +- `purpose'` MUST be `9'`. +- `coin_type'` MUST be `5'` on mainnet (Dash SLIP-44 coin type) and MUST be `1'` on testnet/devnet/regtest (SLIP-44 test coin type), consistent with BIP-44 conventions. +- `account'` MUST be hardened. `0'` is the default account. Additional accounts MAY be used following BIP-44-style multi-account semantics. +- `feature'` MUST be `17'` (Platform payment feature). +- `key_class'` MUST be hardened. The default class for Platform payment receive keys is `0'`. Additional hardened classes MAY be defined by future DIPs; `1'` is reserved for wallet-internal or change-like segregation if a wallet chooses to implement it. +- `index` MUST be non-hardened (`0 ≤ index ≤ 2³¹−1`). +- No BIP-44 change level is used; privacy is obtained by incrementing `index` and optionally segregating with `key_class'`. + +Default account paths: + +- Mainnet: `m/9'/5'/17'/0'/0'/index` +- Testnet/Devnet/Regtest: `m/9'/1'/17'/0'/0'/index` (coin type `1'` for test networks). + +Wallets MAY derive and expose an extended public key at `m/9'/5'/17'/account'/key_class'` (mainnet) or `m/9'/1'/17'/account'/key_class'` (test networks) for watch-only or monitoring. They MUST NOT expose hardened parent levels. + +Accounts follow BIP-44 semantics: `account'` partitions user-controlled sets of Platform payment keys, enabling multiple profiles or organizational separations while preserving hardened isolation between accounts. + + +## Wallet and Hardware Wallet Behavior + +- Wallets MUST derive Platform payment keys only from `m/9'/5'/17'/account'/key_class'/index` (mainnet) or `m/9'/1'/17'/account'/key_class'/index` (test networks). Address encoding of the resulting public keys is specified in DIP-0018. +- Wallets MUST clearly separate Platform balances from Core chain balances in UI and storage. +- Wallets SHOULD rotate addresses by incrementing `index` to avoid reuse; a default gap limit of 20 is RECOMMENDED for discovery. +- Wallets MAY support watch-only by exporting the xpub at `m/9'/5'/17'/account'/key_class'` (mainnet) or `m/9'/1'/17'/account'/key_class'` (test networks). +- Wallets MAY present multiple accounts following BIP-44 semantics (distinct `account'` values), and SHOULD clearly label the active account in UI. +- Hardware wallets MUST whitelist the above derivation path and display a label such as “Dash Platform address (D-address)” when showing or signing. +- Hardware wallets MUST apply the address encodings defined in DIP-0018 and MUST NOT reinterpret these as Core chain P2PKH/P2SH. +- If a wallet does not implement Platform, it simply never derives the `17'` feature path. + +# Rationale + +- **Coin type 5' on mainnet, 1' on test networks:** Mainnet keeps Dash SLIP-44 coin type 5', while testnet/devnet/regtest follow SLIP-44 convention with coin type 1'. This avoids new registry allocations and keeps all Dash features under the established namespaces. +- **DIP-9 vs BIP-44:** DIP-9’s feature level cleanly separates Platform addresses from Core chain funds and from identities/masternodes without overloading BIP-44’s change level or accounts. +- **Feature index 17':** The next available DIP-9 feature after 16' (DashPay) is reserved for Platform payments, avoiding collisions with existing features. +- **Hardened upper levels:** `9'/coin_type'/17'/account'/key_class'` isolate Platform keys from other features and from each other. An xpub leak below `key_class'` cannot compromise hardened parents. +- **Non-hardened leaf index:** Enables watch-only, auditing, and future multisig/shared-custody schemes that rely on unhardened derivation of child public keys. Fully hardened leaves were rejected to preserve these capabilities. +- **Accounts retained:** A hardened `account'` level maintains BIP-44-style multi-account semantics while still isolating Platform keys under the DIP-9 feature branch. +- **No BIP-44 change level:** Platform addresses are not UTXO change outputs; a linear `index` (optionally partitioned by `key_class'`) keeps the model simple for hardware wallets and avoids misuse of the 0/1 change bit. + +# Backwards Compatibility + +- Classic Dash addresses (`X...`, `7...`, `y...`, `8...`) are unaffected. Nodes do not accept D-addresses in Core chain scripts. +- DIP-3/8 masternode derivations and DIP-13 identity derivations remain unchanged. +- Existing seeds stay valid; wallets can add Platform support without migration. +- Wallets unaware of Platform will not derive `m/9'/5'/17'/...` and therefore will not interfere with Platform balances. + +# Reference Implementation + +The following pseudo-code is normative for deriving a Platform payment address: + +``` +function platform_payment_key(seed, account, key_class, index, network): + # seed: BIP-39/BIP-32 seed bytes + # account: hardened int (default 0) + # key_class: hardened int (default 0) + # index: non-hardened child number + # network: "mainnet" or "testnet" + + coin_type = 5' if network == "mainnet" else 1' + path = [9' , coin_type , 17' , account , key_class' , index] + + master_priv, master_chain = bip32_master(seed) # HMAC-SHA512("Bitcoin seed", seed) + child_priv, child_chain = bip32_derive(master_priv, master_chain, path) + + pubkey = secp256k1_compress(secp256k1_point(child_priv)) + payload = RIPEMD160(SHA256(pubkey)) + + return { + "private_key": child_priv, + "public_key": pubkey, + "hash160": payload + } +``` + +Encoding and decoding of these payloads into addresses is specified in DIP-0018. + +# Security Considerations + +- Derivation uses hardened separation at `feature'` and `key_class'`; compromise of a Platform xpub does not expose other features or other key classes. +- Leakage of the xpub at `m/9'/coin_type'/17'/account'/key_class'` allows derivation of all Platform public keys for that key class but does not leak private keys or other features. +- Wallets MUST reject attempts to use D-addresses in Core chain transactions to prevent misdirected funds. +- Hardware wallets MUST show the full derivation path and “Dash Platform address” to reduce key-path confusion attacks. +- The checksum and distinct prefixes mitigate accidental prefix confusion with `X`/`7`/`y`/`8` addresses. + +# Privacy Considerations + +- Platform addresses are unshielded; no zk-SNARK privacy is implied by this DIP. +- Wallets SHOULD avoid address reuse by incrementing `index` and MAY use separate `key_class'` values to segregate user profiles or accounts. +- Wallets SHOULD avoid correlating Platform `index` progression with Core chain BIP-44 indices to reduce cross-layer linkability. +- Sharing xpubs at `m/9'/coin_type'/17'/account'/key_class'` enables watch-only but also enables address graph reconstruction for that class; applications should only share when necessary. + +# Test Vectors + +Mnemonic (test-only): `abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about` +Passphrase: `""` (empty) + +All hex strings are lowercase, big-endian. Address encodings for the HASH160 values are specified in DIP-0018. + +| Vector | Path (mainnet / testnet) | account' | key_class' | index | Private Key (hex) | Compressed Pubkey (hex) | HASH160(pubkey) | +| ------ | ----------------------- | -------- | ---------- | ----- | ----------------- | ----------------------- | --------------- | +| 1 | m/9'/5'/17'/0'/0'/0 (mainnet) / m/9'/1'/17'/0'/0'/0 (test) | 0' | 0' | 0 | 6bca392f43453b7bc33a9532b69221ce74906a8815281637e0c9d0bee35361fe | 03de102ed1fc43cbdb16af02e294945ffaed8e0595d3072f4c592ae80816e6859e | f7da0a2b5cbd4ff6bb2c4d89b67d2f3ffeec0525 | +| 2 | m/9'/5'/17'/0'/0'/1 (mainnet) / m/9'/1'/17'/0'/0'/1 (test) | 0' | 0' | 1 | eef58ce73383f63d5062f281ed0c1e192693c170fbc0049662a73e48a1981523 | 02269ff766fcd04184bc314f5385a04498df215ce1e7193cec9a607f69bc8954da | a5ff0046217fd1c7d238e3e146cc5bfd90832a7e | +| 3 (non-default class) | m/9'/5'/17'/0'/1'/0 (mainnet) / m/9'/1'/17'/0'/1'/0 (test) | 0' | 1' | 0 | cc05b4389712a2e724566914c256217685d781503d7cc05af6642e60260830db | 0317a3ed70c141cffafe00fa8bf458cec119f6fc039a7ba9a6b7303dc65b27bed3 | 6d92674fd64472a3dfcfc3ebcfed7382bf699d7b | + +# DIP-9 Registry Update + +Reserve DIP-9 feature index `17'` for “Platform Payment Addresses”: + +| Feature Index | Feature | DIP | Note | +| ------------- | ------- | --- | ---- | +| `17'` | Platform Payment Addresses | DIP-0017 | Sub-path: `17'/account'/key_class'/index` (default account' = `0'`, key_class' = `0'`) | + +# Copyright + +This document is licensed under the MIT License. diff --git a/dip-0018.md b/dip-0018.md new file mode 100644 index 00000000..fdf2a13d --- /dev/null +++ b/dip-0018.md @@ -0,0 +1,168 @@ +
+  DIP: 0018
+  Title: Dash Platform Payment Address Encodings
+  Author(s): Samuel Westrich
+  Special-Thanks: Dash Platform Team
+  Comments-Summary: No comments yet.
+  Status: Draft
+  Type: Standard
+  Created: 2024-05-23
+  License: MIT License
+  Replaces: -
+  Superseded-By: -
+
+ +## Table of Contents + +1. [Abstract](#abstract) +1. [Motivation](#motivation) +1. [Specification](#specification) + 1. [Address Types](#address-types) + 1. [Encoding](#encoding) + 1. [Network Parameters](#network-parameters) + 1. [Validation](#validation) + 1. [Wallet and Hardware Wallet Behavior](#wallet-and-hardware-wallet-behavior) +1. [Rationale](#rationale) +1. [Backwards Compatibility](#backwards-compatibility) +1. [Reference Implementation](#reference-implementation) +1. [Security Considerations](#security-considerations) +1. [Privacy Considerations](#privacy-considerations) +1. [Test Vectors](#test-vectors) +1. [Copyright](#copyright) + +# Abstract + +This DIP specifies the address encoding formats for Dash Platform payments. It defines Base58Check parameters for Platform pay-to-public-key-hash (P2PKH) addresses derived via DIP-0017 and introduces Platform pay-to-script-hash (P2SH) addresses. Distinct mainnet and testnet prefixes prevent confusion with Dash Core chain addresses. + +# Motivation + +Platform payment keys are derived under DIP-0017. To interoperate between wallets, hardware wallets, and services, a standard encoding with explicit network prefixes and checksum rules is required. Script-hash addresses are also needed for multisig and other script-based Platform payments. + +# Specification + +## Address Types + +- **Platform P2PKH (D-address):** HASH160 of a compressed secp256k1 public key derived per DIP-0017. +- **Platform P2SH:** HASH160 of a Platform script (e.g., multisig or policy script) for receiving Platform payments to scripts. + +## Encoding + +Base58Check is used for all Platform address types. + +Payloads: +- P2PKH payload: `HASH160(pubkey)` where `pubkey` is compressed secp256k1 (33 bytes). +- P2SH payload: `HASH160(script)` where `script` is the raw byte serialization of the Platform script being paid to. + +Encoding algorithm (for either address type): +1. Prepend the network-specific version byte for the address type. +2. Compute checksum = first 4 bytes of `SHA256(SHA256(version || payload))`. +3. Concatenate `version || payload || checksum`. +4. Base58Check-encode the 25-byte result. + +Decoding reverses these steps and verifies checksum and version. + +## Network Parameters + +| Address type | Mainnet version | Expected prefix | Testnet/Devnet/Regtest version | Expected prefix | +| ------------ | --------------- | --------------- | ------------------------------ | ---------------- | +| Platform P2PKH | `0x1e` | `D` | `0x5a` | `d` | +| Platform P2SH | `0x38` | `P` | `0x75` | `p` | + +These prefixes are distinct from Dash Core chain (`X`/`7`/`y`/`8`) and from each other. + +## Validation + +An address is valid for a network if: +1. Base58 decoding yields 25 bytes. +2. The checksum matches the first 4 bytes of `SHA256(SHA256(version || payload))`. +3. The version byte equals the network’s P2PKH or P2SH Platform prefix. +4. Wallets MUST reject Platform addresses when constructing Dash 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-0017. +- Wallets MUST use the P2SH encoding for Platform scripts intended to receive Platform funds. +- Hardware wallets MUST whitelist the version bytes above and display “Dash Platform address” or “Dash Platform script address” as appropriate. +- 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-0017 and then encode using these rules; no alternative prefixes are allowed. + +# Rationale + +- **Base58Check:** Aligns with existing Dash address UX and reduces user confusion compared to introducing a new encoding. +- **Distinct prefixes:** `D/d` for P2PKH and `P/p` for P2SH avoid collisions with Core chain addresses and with each other. +- **Script support:** P2SH enables multisig and policy scripts on Platform without overloading the P2PKH prefix. + +# 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-0017) are unchanged. + +# Reference Implementation + +``` +function encode_platform_address(payload, type, network): + # payload: 20-byte HASH160 + # type: "p2pkh" or "p2sh" + # network: "mainnet" or "testnet" + + if type == "p2pkh": + version = 0x1e if network == "mainnet" else 0x5a + else if type == "p2sh": + version = 0x38 if network == "mainnet" else 0x75 + else: + error("unknown type") + + data = version || payload + checksum = SHA256(SHA256(data))[0:4] + return Base58Encode(data || checksum) + +function decode_platform_address(addr, network): + raw = Base58Decode(addr) + assert len(raw) == 25 + version = raw[0] + payload = raw[1:21] + checksum = raw[21:25] + expect = SHA256(SHA256(raw[0:21]))[0:4] + assert checksum == expect + + valid_p2pkh = (version == 0x1e and network == "mainnet") or (version == 0x5a and network != "mainnet") + valid_p2sh = (version == 0x38 and network == "mainnet") or (version == 0x75 and network != "mainnet") + assert valid_p2pkh or valid_p2sh + + return payload, ("p2pkh" if valid_p2pkh else "p2sh") +``` + +# 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 + +- Base58Check addresses are unshielded; privacy relies on HD key rotation per DIP-0017 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-0017): `abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about` +Passphrase: `""` + +### P2PKH examples (payloads from DIP-0017) + +| Vector | Path (mainnet / testnet) | account' | key_class' | index | HASH160(pubkey) | Mainnet P2PKH | Testnet P2PKH | +| ------ | ----------------------- | -------- | ---------- | ----- | --------------- | ------------- | -------------- | +| 1 | m/9'/5'/17'/0'/0'/0 / m/9'/1'/17'/0'/0'/0 | 0' | 0' | 0 | f7da0a2b5cbd4ff6bb2c4d89b67d2f3ffeec0525 | DTjceJiEqrNkCsSizK65fojEANTKoQMtsR | dSqV2orinasFpYAMGQTLy6uYpW9Dnge563 | +| 2 | m/9'/5'/17'/0'/0'/1 / m/9'/1'/17'/0'/0'/1 | 0' | 0' | 1 | a5ff0046217fd1c7d238e3e146cc5bfd90832a7e | DLGoWhHfAyFcJafRgt2fFN7fxgLqNrfCXm | dZoepEc46ivSfm3VYr8mJeA4hZXYytgkKZ | +| 3 | m/9'/5'/17'/0'/1'/0 / m/9'/1'/17'/0'/1'/0 | 0' | 1' | 0 | 6d92674fd64472a3dfcfc3ebcfed7382bf699d7b | DF8TaTy7YrLdGYqq6cwapSUqdM3qJxLQbo | dFQSkGujaeDNwWTQDDVfbrurQ9ChXXYDov | + +### P2SH example + +- Script (hex): `76a914000102030405060708090a0b0c0d0e0f101112131488ac` + (standard HASH160-to-pubkey script for illustration) +- HASH160(script): `43fa183cf3fb6e9e7dc62b692aeb4fc8d8045636` +- Mainnet P2SH: `Pe8D1pMrEnWsmuj5zCEBhHTcsFE51Asp8k` +- Testnet P2SH: `pBk15SYRYnnKfMENUnYdGw4cG1wcRmSdoh` + +# Copyright + +This document is licensed under the MIT License. From 3aa9b8caddceca6ab3e232b33c4a69c2866f0a84 Mon Sep 17 00:00:00 2001 From: QuantumExplorer Date: Fri, 28 Nov 2025 18:04:18 +0700 Subject: [PATCH 2/7] Update dip-0017.md --- dip-0017.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dip-0017.md b/dip-0017.md index b2e04936..073cc615 100644 --- a/dip-0017.md +++ b/dip-0017.md @@ -35,13 +35,13 @@ This DIP defines Dash Platform payment addresses (“D-addresses”) and their h # Motivation -Dash Platform enables value transfers distinct from Dash Core chain (L1) UTXO transactions. Wallets require an unambiguous address type, network-specific encodings, and deterministic derivation paths that coexist with BIP-44 Core chain funds and existing DIP-9 features (masternodes, identities, DashPay). This DIP provides a single standard so wallets, hardware wallets, and services can implement Platform payments without changing seeds or coin types. +Dash Platform enables value transfers distinct from Dash Core chain UTXO transactions. Wallets require an unambiguous address type, network-specific encodings, and deterministic derivation paths that coexist with BIP-44 Core chain funds and existing DIP-9 features (masternodes, identities, DashPay). This DIP provides a single standard so wallets, hardware wallets, and services can implement Platform payments. # Specification ## Overview -Platform payment keys identify recipients of Platform-level value—specifically Dash Credits (DCredits), the form of Dash held on the Platform chain—and may also be used for other Platform payments. They are derived from a single secp256k1 key pair, not from scripts. They are not valid Dash Core chain addresses and SHOULD NOT be used in Core chain transactions. Address encoding for these keys is specified in DIP-0018. +Platform payment keys identify recipients of value on Dash Platform. This value includes Dash Credits, which represent DASH held on Platform, as well as other Platform-based payments. These keys are independent of Dash Platform identities and do not belong to an identity’s key set. Instead, they function as standalone payment keys that hold value outside of any identity. They use a single secp256k1 key pair and are not script-based. They are not valid Dash Core chain addresses and MUST NOT be used for Core chain transactions. Their encoding format is specified in DIP-0018. ## Derivation Path Definition @@ -74,11 +74,11 @@ Accounts follow BIP-44 semantics: `account'` partitions user-controlled sets of ## Wallet and Hardware Wallet Behavior - Wallets MUST derive Platform payment keys only from `m/9'/5'/17'/account'/key_class'/index` (mainnet) or `m/9'/1'/17'/account'/key_class'/index` (test networks). Address encoding of the resulting public keys is specified in DIP-0018. -- Wallets MUST clearly separate Platform balances from Core chain balances in UI and storage. +- Wallets SHOULD clearly separate Platform chain balances from Core chain balances in UI and storage. - Wallets SHOULD rotate addresses by incrementing `index` to avoid reuse; a default gap limit of 20 is RECOMMENDED for discovery. - Wallets MAY support watch-only by exporting the xpub at `m/9'/5'/17'/account'/key_class'` (mainnet) or `m/9'/1'/17'/account'/key_class'` (test networks). - Wallets MAY present multiple accounts following BIP-44 semantics (distinct `account'` values), and SHOULD clearly label the active account in UI. -- Hardware wallets MUST whitelist the above derivation path and display a label such as “Dash Platform address (D-address)” when showing or signing. +- Hardware wallets MUST whitelist the above derivation path and display a label such as “Dash Platform address” when showing or signing. - Hardware wallets MUST apply the address encodings defined in DIP-0018 and MUST NOT reinterpret these as Core chain P2PKH/P2SH. - If a wallet does not implement Platform, it simply never derives the `17'` feature path. From 20b20448b488949c1950584da576a2d8033a3a3e Mon Sep 17 00:00:00 2001 From: thephez Date: Wed, 3 Dec 2025 16:39:55 -0500 Subject: [PATCH 3/7] chore: dip-17/18 suggestions (#172) * chore: lint fixes * fix: correct order of feature and account * chore: update copyright * docs: add prior work sections and improve formatting in DIP-17/18 Add Prior Work sections referencing DIP-0009, BIP-0032, and BIP-0044 in DIP-17 and DIP-0017 in DIP-18. Convert path examples to table format, add key_class forward compatibility note, and fix minor formatting. * docs: add new dips to readme and update create date * docs: standardize dip number representation and add links * docs: add more prior work references --- README.md | 2 + dip-0017.md | 110 ++++++++++++++++++++++++++++------------------------ dip-0018.md | 69 +++++++++++++++++--------------- 3 files changed, 100 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index 3f565747..83f8a054 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,8 @@ Number | Layer | Title | Owner | Type | Status [14](dip-0014.md) | Applications | Extended Key Derivation using 256-Bit Unsigned Integers | Samuel Westrich | Informational | Proposed [15](dip-0015.md) | Applications | DashPay | Samuel Westrich, Eric Britten | Standard | Proposed [16](dip-0016.md) | Applications | Headers First Synchronization on Simple Payment Verification Wallets | Samuel Westrich | Informational | Proposed +[17](dip-0017.md) | Consensus | Dash Platform Payment Addresses and HD Derivation | Samuel Westrich | Standard | Proposed +[18](dip-0018.md) | Consensus | Dash Platform Payment Address Encodings | Samuel Westrich | Standard | Proposed [20](dip-0020.md) | Consensus | Dash Opcode Updates | Mart Mangus | Standard | Final [21](dip-0021.md) | Consensus | LLMQ DKG Data Sharing | dustinface | Standard | Final [22](dip-0022.md) | Consensus | Making InstantSend Deterministic using Quorum Cycles | Samuel Westrich, UdjinM6 | Standard | Final diff --git a/dip-0017.md b/dip-0017.md index 073cc615..619b85d9 100644 --- a/dip-0017.md +++ b/dip-0017.md @@ -6,7 +6,7 @@ Comments-Summary: No comments yet. Status: Draft Type: Standard - Created: 2024-05-23 + Created: 2025-11-28 License: MIT License Replaces: - Superseded-By: - @@ -16,6 +16,7 @@ 1. [Abstract](#abstract) 1. [Motivation](#motivation) +1. [Prior Work](#prior-work) 1. [Specification](#specification) 1. [Overview](#overview) 1. [Derivation Path Definition](#derivation-path-definition) @@ -31,79 +32,88 @@ # Abstract -This DIP defines Dash Platform payment addresses (“D-addresses”) and their hierarchical deterministic (HD) derivation under DIP-9. It uses Dash coin type 5' on mainnet and coin type 1' on test networks, and introduces a new DIP-9 feature index for Platform payments. The specification standardizes derivation paths (including account separation) and wallet/hardware wallet guidance for Platform payment keys. Address encoding (version bytes and formats) and script-hash address formats are defined in DIP-0018. +This DIP defines Dash Platform payment addresses (“D-addresses”) and their hierarchical deterministic (HD) derivation under [DIP-9](dip-0009.md). It uses Dash coin type 5' on mainnet and coin type 1' on test networks, and introduces a new [DIP-9](dip-0009.md) feature index for Platform payments. The specification standardizes derivation paths (including account separation) and wallet/hardware wallet guidance for Platform payment keys. Address encoding (version bytes and formats) and script-hash address formats are defined in [DIP-18](dip-0018.md). # Motivation -Dash Platform enables value transfers distinct from Dash Core chain UTXO transactions. Wallets require an unambiguous address type, network-specific encodings, and deterministic derivation paths that coexist with BIP-44 Core chain funds and existing DIP-9 features (masternodes, identities, DashPay). This DIP provides a single standard so wallets, hardware wallets, and services can implement Platform payments. +Dash Platform enables value transfers distinct from Dash Core chain UTXO transactions. Wallets require an unambiguous address type, network-specific encodings, and deterministic derivation paths that coexist with BIP-44 Core chain funds and existing [DIP-9](dip-0009.md) features (masternodes, identities, DashPay). This DIP provides a single standard so wallets, hardware wallets, and services can implement Platform payments. + +# Prior Work + +* [DIP-0009: Feature Derivation Paths](https://github.com/dashpay/dips/blob/master/dip-0009.md) +* [DIP-0013: Identities in Hierarchical Deterministic Wallets](https://github.com/dashpay/dips/blob/master/dip-0013.md) +* [DIP-0015: DashPay](https://github.com/dashpay/dips/blob/master/dip-0015.md) +* [BIP-0032: Hierarchical Deterministic Wallets](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) +* [BIP-0044: Multi-Account Hierarchy for Deterministic Wallets](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) # Specification ## Overview -Platform payment keys identify recipients of value on Dash Platform. This value includes Dash Credits, which represent DASH held on Platform, as well as other Platform-based payments. These keys are independent of Dash Platform identities and do not belong to an identity’s key set. Instead, they function as standalone payment keys that hold value outside of any identity. They use a single secp256k1 key pair and are not script-based. They are not valid Dash Core chain addresses and MUST NOT be used for Core chain transactions. Their encoding format is specified in DIP-0018. +Platform payment keys identify recipients of value on Dash Platform. This value includes Dash Credits, which represent DASH held on Platform, as well as other Platform-based payments. These keys are independent of Dash Platform identities and do not belong to an identity’s key set. Instead, they function as standalone payment keys that hold value outside of any identity. They use a single secp256k1 key pair and are not script-based. They are not valid Dash Core chain addresses and MUST NOT be used for Core chain transactions. Their encoding format is specified in [DIP-18](dip-0018.md). ## Derivation Path Definition -The Platform payment feature is assigned DIP-9 feature index `17'`. The canonical derivation path is: +The Platform payment feature is assigned [DIP-9](dip-0009.md) feature index `17'`. The canonical derivation path is: -``` +```text m / 9' / coin_type' / 17' / account' / key_class' / index ``` Normative requirements: -- `purpose'` MUST be `9'`. -- `coin_type'` MUST be `5'` on mainnet (Dash SLIP-44 coin type) and MUST be `1'` on testnet/devnet/regtest (SLIP-44 test coin type), consistent with BIP-44 conventions. -- `account'` MUST be hardened. `0'` is the default account. Additional accounts MAY be used following BIP-44-style multi-account semantics. -- `feature'` MUST be `17'` (Platform payment feature). -- `key_class'` MUST be hardened. The default class for Platform payment receive keys is `0'`. Additional hardened classes MAY be defined by future DIPs; `1'` is reserved for wallet-internal or change-like segregation if a wallet chooses to implement it. -- `index` MUST be non-hardened (`0 ≤ index ≤ 2³¹−1`). -- No BIP-44 change level is used; privacy is obtained by incrementing `index` and optionally segregating with `key_class'`. +* `purpose'` MUST be `9'`. +* `coin_type'` MUST be `5'` on mainnet (Dash SLIP-44 coin type) and MUST be `1'` on testnet/devnet/regtest (SLIP-44 test coin type), consistent with BIP-44 conventions. +* `feature'` MUST be `17'` (Platform payment feature). +* `account'` MUST be hardened. `0'` is the default account. Additional accounts MAY be used following BIP-44-style multi-account semantics. +* `key_class'` MUST be hardened. The default class for Platform payment receive keys is `0'`. Additional hardened classes MAY be defined by future DIPs; `1'` is reserved for wallet-internal or change-like segregation if a wallet chooses to implement it. Wallets MUST ignore unknown key_class values rather than rejecting the entire account. +* `index` MUST be non-hardened (`0 ≤ index ≤ 2³¹−1`). +* No BIP-44 change level is used; privacy is obtained by incrementing `index` and optionally segregating with `key_class'`. Default account paths: -- Mainnet: `m/9'/5'/17'/0'/0'/index` -- Testnet/Devnet/Regtest: `m/9'/1'/17'/0'/0'/index` (coin type `1'` for test networks). +| Network(s) | Default account path | +|-|-| +| Mainnet | `m/9'/5'/17'/0'/0'/index` | +| Testnet / Devnet / Regtest | `m/9'/1'/17'/0'/0'/index` (coin type `1'` for test networks) | Wallets MAY derive and expose an extended public key at `m/9'/5'/17'/account'/key_class'` (mainnet) or `m/9'/1'/17'/account'/key_class'` (test networks) for watch-only or monitoring. They MUST NOT expose hardened parent levels. Accounts follow BIP-44 semantics: `account'` partitions user-controlled sets of Platform payment keys, enabling multiple profiles or organizational separations while preserving hardened isolation between accounts. - ## Wallet and Hardware Wallet Behavior -- Wallets MUST derive Platform payment keys only from `m/9'/5'/17'/account'/key_class'/index` (mainnet) or `m/9'/1'/17'/account'/key_class'/index` (test networks). Address encoding of the resulting public keys is specified in DIP-0018. -- Wallets SHOULD clearly separate Platform chain balances from Core chain balances in UI and storage. -- Wallets SHOULD rotate addresses by incrementing `index` to avoid reuse; a default gap limit of 20 is RECOMMENDED for discovery. -- Wallets MAY support watch-only by exporting the xpub at `m/9'/5'/17'/account'/key_class'` (mainnet) or `m/9'/1'/17'/account'/key_class'` (test networks). -- Wallets MAY present multiple accounts following BIP-44 semantics (distinct `account'` values), and SHOULD clearly label the active account in UI. -- Hardware wallets MUST whitelist the above derivation path and display a label such as “Dash Platform address” when showing or signing. -- Hardware wallets MUST apply the address encodings defined in DIP-0018 and MUST NOT reinterpret these as Core chain P2PKH/P2SH. -- If a wallet does not implement Platform, it simply never derives the `17'` feature path. +* Wallets MUST derive Platform payment keys only from `m/9'/5'/17'/account'/key_class'/index` (mainnet) or `m/9'/1'/17'/account'/key_class'/index` (test networks). Address encoding of the resulting public keys is specified in [DIP-18](dip-0018.md). +* Wallets SHOULD clearly separate Platform chain balances from Core chain balances in UI and storage. +* Wallets SHOULD rotate addresses by incrementing `index` to avoid reuse; a default gap limit of 20 is RECOMMENDED for discovery. +* Wallets MAY support watch-only by exporting the xpub at `m/9'/5'/17'/account'/key_class'` (mainnet) or `m/9'/1'/17'/account'/key_class'` (test networks). +* Wallets MAY present multiple accounts following BIP-44 semantics (distinct `account'` values), and SHOULD clearly label the active account in UI. +* Hardware wallets MUST whitelist the above derivation path and display a label such as “Dash Platform address” when showing or signing. +* Hardware wallets MUST apply the address encodings defined in [DIP-18](dip-0018.md) and MUST NOT reinterpret these as Core chain P2PKH/P2SH. +* If a wallet does not implement Platform, it simply never derives the `17'` feature path. # Rationale -- **Coin type 5' on mainnet, 1' on test networks:** Mainnet keeps Dash SLIP-44 coin type 5', while testnet/devnet/regtest follow SLIP-44 convention with coin type 1'. This avoids new registry allocations and keeps all Dash features under the established namespaces. -- **DIP-9 vs BIP-44:** DIP-9’s feature level cleanly separates Platform addresses from Core chain funds and from identities/masternodes without overloading BIP-44’s change level or accounts. -- **Feature index 17':** The next available DIP-9 feature after 16' (DashPay) is reserved for Platform payments, avoiding collisions with existing features. -- **Hardened upper levels:** `9'/coin_type'/17'/account'/key_class'` isolate Platform keys from other features and from each other. An xpub leak below `key_class'` cannot compromise hardened parents. -- **Non-hardened leaf index:** Enables watch-only, auditing, and future multisig/shared-custody schemes that rely on unhardened derivation of child public keys. Fully hardened leaves were rejected to preserve these capabilities. -- **Accounts retained:** A hardened `account'` level maintains BIP-44-style multi-account semantics while still isolating Platform keys under the DIP-9 feature branch. -- **No BIP-44 change level:** Platform addresses are not UTXO change outputs; a linear `index` (optionally partitioned by `key_class'`) keeps the model simple for hardware wallets and avoids misuse of the 0/1 change bit. +* **Coin type 5' on mainnet, 1' on test networks:** Mainnet keeps Dash SLIP-44 coin type 5', while testnet/devnet/regtest follow SLIP-44 convention with coin type 1'. This avoids new registry allocations and keeps all Dash features under the established namespaces. +* **DIP-9 vs BIP-44:** DIP-9’s feature level cleanly separates Platform addresses from Core chain funds and from identities/masternodes without overloading BIP-44’s change level or accounts. +* **Feature index 17':** The next available [DIP-9](dip-0009.md) feature after 16' (DashPay) is reserved for Platform payments, avoiding collisions with existing features. +* **Hardened upper levels:** `9'/coin_type'/17'/account'/key_class'` isolate Platform keys from other features and from each other. An xpub leak below `key_class'` cannot compromise hardened parents. +* **Non-hardened leaf index:** Enables watch-only, auditing, and future multisig/shared-custody schemes that rely on unhardened derivation of child public keys. Fully hardened leaves were rejected to preserve these capabilities. +* **Accounts retained:** A hardened `account'` level maintains BIP-44-style multi-account semantics while still isolating Platform keys under the [DIP-9](dip-0009.md) feature branch. +* **No BIP-44 change level:** Platform addresses are not UTXO change outputs; a linear `index` (optionally partitioned by `key_class'`) keeps the model simple for hardware wallets and avoids misuse of the 0/1 change bit. # Backwards Compatibility -- Classic Dash addresses (`X...`, `7...`, `y...`, `8...`) are unaffected. Nodes do not accept D-addresses in Core chain scripts. -- DIP-3/8 masternode derivations and DIP-13 identity derivations remain unchanged. -- Existing seeds stay valid; wallets can add Platform support without migration. -- Wallets unaware of Platform will not derive `m/9'/5'/17'/...` and therefore will not interfere with Platform balances. +* Classic Dash addresses (`X...`, `7...`, `y...`, `8...`) are unaffected. Nodes do not accept D-addresses in Core chain scripts. +* DIP-[3](dip-0003.md)/[8](dip-0008.md) masternode derivations and [DIP-13](dip-0013.md) identity derivations remain unchanged. +* Existing seeds stay valid; wallets can add Platform support without migration. +* Wallets unaware of Platform will not derive `m/9'/5'/17'/...` and therefore will not interfere with Platform balances. # Reference Implementation The following pseudo-code is normative for deriving a Platform payment address: -``` +```text function platform_payment_key(seed, account, key_class, index, network): # seed: BIP-39/BIP-32 seed bytes # account: hardened int (default 0) @@ -127,29 +137,29 @@ function platform_payment_key(seed, account, key_class, index, network): } ``` -Encoding and decoding of these payloads into addresses is specified in DIP-0018. +Encoding and decoding of these payloads into addresses is specified in [DIP-18](dip-0018.md). # Security Considerations -- Derivation uses hardened separation at `feature'` and `key_class'`; compromise of a Platform xpub does not expose other features or other key classes. -- Leakage of the xpub at `m/9'/coin_type'/17'/account'/key_class'` allows derivation of all Platform public keys for that key class but does not leak private keys or other features. -- Wallets MUST reject attempts to use D-addresses in Core chain transactions to prevent misdirected funds. -- Hardware wallets MUST show the full derivation path and “Dash Platform address” to reduce key-path confusion attacks. -- The checksum and distinct prefixes mitigate accidental prefix confusion with `X`/`7`/`y`/`8` addresses. +* Derivation uses hardened separation at `feature'` and `key_class'`; compromise of a Platform xpub does not expose other features or other key classes. +* Leakage of the xpub at `m/9'/coin_type'/17'/account'/key_class'` allows derivation of all Platform public keys for that key class but does not leak private keys or other features. +* Wallets MUST reject attempts to use D-addresses in Core chain transactions to prevent misdirected funds. +* Hardware wallets MUST show the full derivation path and “Dash Platform address” to reduce key-path confusion attacks. +* The checksum and distinct prefixes mitigate accidental prefix confusion with `X`/`7`/`y`/`8` addresses. # Privacy Considerations -- Platform addresses are unshielded; no zk-SNARK privacy is implied by this DIP. -- Wallets SHOULD avoid address reuse by incrementing `index` and MAY use separate `key_class'` values to segregate user profiles or accounts. -- Wallets SHOULD avoid correlating Platform `index` progression with Core chain BIP-44 indices to reduce cross-layer linkability. -- Sharing xpubs at `m/9'/coin_type'/17'/account'/key_class'` enables watch-only but also enables address graph reconstruction for that class; applications should only share when necessary. +* Platform addresses are unshielded; no zk-SNARK privacy is implied by this DIP. +* Wallets SHOULD avoid address reuse by incrementing `index` and MAY use separate `key_class'` values to segregate user profiles or accounts. +* Wallets SHOULD avoid correlating Platform `index` progression with Core chain BIP-44 indices to reduce cross-layer linkability. +* Sharing xpubs at `m/9'/coin_type'/17'/account'/key_class'` enables watch-only but also enables address graph reconstruction for that class; applications should only share when necessary. # Test Vectors Mnemonic (test-only): `abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about` Passphrase: `""` (empty) -All hex strings are lowercase, big-endian. Address encodings for the HASH160 values are specified in DIP-0018. +All hex strings are lowercase, big-endian. Address encodings for the HASH160 values are specified in [DIP-18](dip-0018.md). | Vector | Path (mainnet / testnet) | account' | key_class' | index | Private Key (hex) | Compressed Pubkey (hex) | HASH160(pubkey) | | ------ | ----------------------- | -------- | ---------- | ----- | ----------------- | ----------------------- | --------------- | @@ -159,12 +169,12 @@ All hex strings are lowercase, big-endian. Address encodings for the HASH160 val # DIP-9 Registry Update -Reserve DIP-9 feature index `17'` for “Platform Payment Addresses”: +Reserve [DIP-9](dip-0009.md) feature index `17'` for “Platform Payment Addresses”: | Feature Index | Feature | DIP | Note | | ------------- | ------- | --- | ---- | -| `17'` | Platform Payment Addresses | DIP-0017 | Sub-path: `17'/account'/key_class'/index` (default account' = `0'`, key_class' = `0'`) | +| `17'` | Platform Payment Addresses | DIP-17 | Sub-path: `17'/account'/key_class'/index` (default account' = `0'`, key_class' = `0'`) | # Copyright -This document is licensed under the MIT License. +Copyright (c) 2025 Dash Core Group, Inc. [Licensed under the MIT License](https://opensource.org/licenses/MIT) diff --git a/dip-0018.md b/dip-0018.md index fdf2a13d..0c1d2d4a 100644 --- a/dip-0018.md +++ b/dip-0018.md @@ -6,7 +6,7 @@ Comments-Summary: No comments yet. Status: Draft Type: Standard - Created: 2024-05-23 + Created: 2025-11-28 License: MIT License Replaces: - Superseded-By: - @@ -16,6 +16,7 @@ 1. [Abstract](#abstract) 1. [Motivation](#motivation) +1. [Prior Work](#prior-work) 1. [Specification](#specification) 1. [Address Types](#address-types) 1. [Encoding](#encoding) @@ -32,28 +33,34 @@ # Abstract -This DIP specifies the address encoding formats for Dash Platform payments. It defines Base58Check parameters for Platform pay-to-public-key-hash (P2PKH) addresses derived via DIP-0017 and introduces Platform pay-to-script-hash (P2SH) addresses. Distinct mainnet and testnet prefixes prevent confusion with Dash Core chain addresses. +This DIP specifies the address encoding formats for Dash Platform payments. It defines Base58Check parameters for Platform pay-to-public-key-hash (P2PKH) addresses derived via [DIP-17](dip-0017.md) and introduces Platform pay-to-script-hash (P2SH) addresses. Distinct mainnet and testnet prefixes prevent confusion with Dash Core chain addresses. # Motivation -Platform payment keys are derived under DIP-0017. To interoperate between wallets, hardware wallets, and services, a standard encoding with explicit network prefixes and checksum rules is required. Script-hash addresses are also needed for multisig and other script-based Platform payments. +Platform payment keys are derived under [DIP-17](dip-0017.md). To interoperate between wallets, hardware wallets, and services, a standard encoding with explicit network prefixes and checksum rules is required. Script-hash addresses are also needed for multisig and other script-based Platform payments. + +# Prior Work + +* [DIP-0017: Dash Platform Payment Addresses and HD Derivation](https://github.com/dashpay/dips/blob/master/dip-0017.md) # Specification ## Address Types -- **Platform P2PKH (D-address):** HASH160 of a compressed secp256k1 public key derived per DIP-0017. -- **Platform P2SH:** HASH160 of a Platform script (e.g., multisig or policy script) for receiving Platform payments to scripts. +* **Platform P2PKH (D-address):** HASH160 of a compressed secp256k1 public key derived per [DIP-17](dip-0017.md). +* **Platform P2SH:** HASH160 of a Platform script (e.g., multisig or policy script) for receiving Platform payments to scripts. ## Encoding Base58Check is used for all Platform address types. Payloads: -- P2PKH payload: `HASH160(pubkey)` where `pubkey` is compressed secp256k1 (33 bytes). -- P2SH payload: `HASH160(script)` where `script` is the raw byte serialization of the Platform script being paid to. + +* P2PKH payload: `HASH160(pubkey)` where `pubkey` is compressed secp256k1 (33 bytes). +* P2SH payload: `HASH160(script)` where `script` is the raw byte serialization of the Platform script being paid to. Encoding algorithm (for either address type): + 1. Prepend the network-specific version byte for the address type. 2. Compute checksum = first 4 bytes of `SHA256(SHA256(version || payload))`. 3. Concatenate `version || payload || checksum`. @@ -73,6 +80,7 @@ These prefixes are distinct from Dash Core chain (`X`/`7`/`y`/`8`) and from each ## Validation An address is valid for a network if: + 1. Base58 decoding yields 25 bytes. 2. The checksum matches the first 4 bytes of `SHA256(SHA256(version || payload))`. 3. The version byte equals the network’s P2PKH or P2SH Platform prefix. @@ -80,25 +88,25 @@ An address is valid for a network if: ## Wallet and Hardware Wallet Behavior -- Wallets MUST use the P2PKH encoding above for public keys derived per DIP-0017. -- Wallets MUST use the P2SH encoding for Platform scripts intended to receive Platform funds. -- Hardware wallets MUST whitelist the version bytes above and display “Dash Platform address” or “Dash Platform script address” as appropriate. -- 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-0017 and then encode using these rules; no alternative prefixes are allowed. +* Wallets MUST use the P2PKH encoding above for public keys derived per [DIP-17](dip-0017.md). +* Wallets MUST use the P2SH encoding for Platform scripts intended to receive Platform funds. +* Hardware wallets MUST whitelist the version bytes above and display “Dash Platform address” or “Dash Platform script address” as appropriate. +* 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](dip-0017.md) and then encode using these rules; no alternative prefixes are allowed. # Rationale -- **Base58Check:** Aligns with existing Dash address UX and reduces user confusion compared to introducing a new encoding. -- **Distinct prefixes:** `D/d` for P2PKH and `P/p` for P2SH avoid collisions with Core chain addresses and with each other. -- **Script support:** P2SH enables multisig and policy scripts on Platform without overloading the P2PKH prefix. +* **Base58Check:** Aligns with existing Dash address UX and reduces user confusion compared to introducing a new encoding. +* **Distinct prefixes:** `D/d` for P2PKH and `P/p` for P2SH avoid collisions with Core chain addresses and with each other. +* **Script support:** P2SH enables multisig and policy scripts on Platform without overloading the P2PKH prefix. # 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-0017) are unchanged. +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](dip-0017.md)) are unchanged. # Reference Implementation -``` +```text function encode_platform_address(payload, type, network): # payload: 20-byte HASH160 # type: "p2pkh" or "p2sh" @@ -133,21 +141,21 @@ function decode_platform_address(addr, network): # 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. +* 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 -- Base58Check addresses are unshielded; privacy relies on HD key rotation per DIP-0017 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. +* Base58Check addresses are unshielded; privacy relies on HD key rotation per [DIP-17](dip-0017.md) 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-0017): `abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about` +Mnemonic (shared with [DIP-17](dip-0017.md)): `abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about` Passphrase: `""` -### P2PKH examples (payloads from DIP-0017) +## P2PKH examples (payloads from DIP-17) | Vector | Path (mainnet / testnet) | account' | key_class' | index | HASH160(pubkey) | Mainnet P2PKH | Testnet P2PKH | | ------ | ----------------------- | -------- | ---------- | ----- | --------------- | ------------- | -------------- | @@ -155,14 +163,13 @@ Passphrase: `""` | 2 | m/9'/5'/17'/0'/0'/1 / m/9'/1'/17'/0'/0'/1 | 0' | 0' | 1 | a5ff0046217fd1c7d238e3e146cc5bfd90832a7e | DLGoWhHfAyFcJafRgt2fFN7fxgLqNrfCXm | dZoepEc46ivSfm3VYr8mJeA4hZXYytgkKZ | | 3 | m/9'/5'/17'/0'/1'/0 / m/9'/1'/17'/0'/1'/0 | 0' | 1' | 0 | 6d92674fd64472a3dfcfc3ebcfed7382bf699d7b | DF8TaTy7YrLdGYqq6cwapSUqdM3qJxLQbo | dFQSkGujaeDNwWTQDDVfbrurQ9ChXXYDov | -### P2SH example +## P2SH example -- Script (hex): `76a914000102030405060708090a0b0c0d0e0f101112131488ac` - (standard HASH160-to-pubkey script for illustration) -- HASH160(script): `43fa183cf3fb6e9e7dc62b692aeb4fc8d8045636` -- Mainnet P2SH: `Pe8D1pMrEnWsmuj5zCEBhHTcsFE51Asp8k` -- Testnet P2SH: `pBk15SYRYnnKfMENUnYdGw4cG1wcRmSdoh` +* Script (hex): `76a914000102030405060708090a0b0c0d0e0f101112131488ac` (standard HASH160-to-pubkey script for illustration) +* HASH160(script): `43fa183cf3fb6e9e7dc62b692aeb4fc8d8045636` +* Mainnet P2SH: `Pe8D1pMrEnWsmuj5zCEBhHTcsFE51Asp8k` +* Testnet P2SH: `pBk15SYRYnnKfMENUnYdGw4cG1wcRmSdoh` # Copyright -This document is licensed under the MIT License. +Copyright (c) 2025 Dash Core Group, Inc. [Licensed under the MIT License](https://opensource.org/licenses/MIT) From 0f02690acc857beb8c29c8c7bc86b45542e2980b Mon Sep 17 00:00:00 2001 From: thephez Date: Thu, 11 Dec 2025 10:10:50 -0500 Subject: [PATCH 4/7] Update dip-0017.md Co-authored-by: PastaPastaPasta <6443210+PastaPastaPasta@users.noreply.github.com> --- dip-0017.md | 1 - 1 file changed, 1 deletion(-) diff --git a/dip-0017.md b/dip-0017.md index 619b85d9..21ce16dd 100644 --- a/dip-0017.md +++ b/dip-0017.md @@ -149,7 +149,6 @@ Encoding and decoding of these payloads into addresses is specified in [DIP-18]( # Privacy Considerations -* Platform addresses are unshielded; no zk-SNARK privacy is implied by this DIP. * Wallets SHOULD avoid address reuse by incrementing `index` and MAY use separate `key_class'` values to segregate user profiles or accounts. * Wallets SHOULD avoid correlating Platform `index` progression with Core chain BIP-44 indices to reduce cross-layer linkability. * Sharing xpubs at `m/9'/coin_type'/17'/account'/key_class'` enables watch-only but also enables address graph reconstruction for that class; applications should only share when necessary. From 94f423dd97bf7378c202bf4c8435c89f3b072be5 Mon Sep 17 00:00:00 2001 From: thephez Date: Thu, 11 Dec 2025 15:16:16 -0500 Subject: [PATCH 5/7] feat(dip-18): switch to bech32m encoding with reference implementation (#173) * feat(dip-18): switch to bech32m encoding with reference implementation Replace Base58Check encoding with bech32m (BIP-350) for Platform addresses. Add Python reference implementation with full DIP-17 test vector validation. * chore: update authors list for dip-18 * chore(dip18): update bech2 hrp to (t)dashevo * docs(dip18): formatting and minor updates * fix(dip18): add BIP-39 NFKD normalization to mnemonic_to_seed Normalize mnemonic and passphrase with NFKD before UTF-8 encoding per BIP-39 spec. * refactor(dip18): use verbatim BIP-350 reference implementation Replace custom Bech32m implementation with exact code from sipa's reference at github.com/sipa/bech32. Adds MIT license header and proper attribution. * docs(dip18): reference Python implementation in spec --- README.md | 2 +- dip-0018.md | 250 ++++++++++++++++-------- dip-0018/bech32.py | 467 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 635 insertions(+), 84 deletions(-) create mode 100644 dip-0018/bech32.py diff --git a/README.md b/README.md index 83f8a054..4c701011 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Number | Layer | Title | Owner | Type | Status [15](dip-0015.md) | Applications | DashPay | Samuel Westrich, Eric Britten | Standard | Proposed [16](dip-0016.md) | Applications | Headers First Synchronization on Simple Payment Verification Wallets | Samuel Westrich | Informational | Proposed [17](dip-0017.md) | Consensus | Dash Platform Payment Addresses and HD Derivation | Samuel Westrich | Standard | Proposed -[18](dip-0018.md) | Consensus | Dash Platform Payment Address Encodings | Samuel Westrich | Standard | Proposed +[18](dip-0018.md) | Consensus | Dash Platform Payment Address Encodings | Samuel Westrich, thephez | Standard | Proposed [20](dip-0020.md) | Consensus | Dash Opcode Updates | Mart Mangus | Standard | Final [21](dip-0021.md) | Consensus | LLMQ DKG Data Sharing | dustinface | Standard | Final [22](dip-0022.md) | Consensus | Making InstantSend Deterministic using Quorum Cycles | Samuel Westrich, UdjinM6 | Standard | Final diff --git a/dip-0018.md b/dip-0018.md index 0c1d2d4a..361fd604 100644 --- a/dip-0018.md +++ b/dip-0018.md @@ -1,7 +1,7 @@
   DIP: 0018
   Title: Dash Platform Payment Address Encodings
-  Author(s): Samuel Westrich
+  Author(s): Samuel Westrich, thephez
   Special-Thanks: Dash Platform Team
   Comments-Summary: No comments yet.
   Status: Draft
@@ -31,145 +31,229 @@
 1. [Test Vectors](#test-vectors)
 1. [Copyright](#copyright)
 
-# Abstract
+## Abstract
 
-This DIP specifies the address encoding formats for Dash Platform payments. It defines Base58Check parameters for Platform pay-to-public-key-hash (P2PKH) addresses derived via [DIP-17](dip-0017.md) and introduces Platform pay-to-script-hash (P2SH) addresses. Distinct mainnet and testnet prefixes prevent confusion with Dash Core chain addresses.
+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](dip-0017.md), 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
+## Motivation
 
-Platform payment keys are derived under [DIP-17](dip-0017.md). To interoperate between wallets, hardware wallets, and services, a standard encoding with explicit network prefixes and checksum rules is required. Script-hash addresses are also needed for multisig and other script-based Platform payments.
+Platform payment keys are derived under [DIP-17](dip-0017.md). 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
+## Prior Work
 
 * [DIP-0017: Dash Platform Payment Addresses and HD Derivation](https://github.com/dashpay/dips/blob/master/dip-0017.md)
+* [BIP-0173: bech32 format](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki)
+* [BIP-0350: bech32m format for modern checksums](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki)
 
-# Specification
+## Specification
 
-## Address Types
+### Address Types
 
-* **Platform P2PKH (D-address):** HASH160 of a compressed secp256k1 public key derived per [DIP-17](dip-0017.md).
-* **Platform P2SH:** HASH160 of a Platform script (e.g., multisig or policy script) for receiving Platform payments to scripts.
+* **Platform P2PKH:** `HASH160(pubkey)` where `pubkey` is a compressed secp256k1 public key derived per [DIP-17](dip-0017.md).
+* **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
 
-Base58Check is used for all Platform address types.
+#### Encoding Algorithm Summary
 
-Payloads:
+Encoding a Dash Platform address uses the bech32m format defined in [BIP-350](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki), with the general encoding rules inherited from [BIP-173](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki).
 
-* P2PKH payload: `HASH160(pubkey)` where `pubkey` is compressed secp256k1 (33 bytes).
-* P2SH payload: `HASH160(script)` where `script` is the raw byte serialization of the Platform script being paid to.
+Given:
 
-Encoding algorithm (for either address type):
+* `hrp`: the network human-readable prefix (e.g., `dashevo`, `tdashevo`)
+* `type_byte`: `0x00` for P2PKH or `0x01` for P2SH
+* `hash160`: a 20-byte `HASH160(pubkey or script)` value
 
-1. Prepend the network-specific version byte for the address type.
-2. Compute checksum = first 4 bytes of `SHA256(SHA256(version || payload))`.
-3. Concatenate `version || payload || checksum`.
-4. Base58Check-encode the 25-byte result.
+The address MUST be encoded as follows:
 
-Decoding reverses these steps and verifies checksum and version.
+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](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki), with padding enabled
+3. Compute the bech32m checksum using the algorithm defined in [BIP-350](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki#appendix-checksum-design--properties), 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](https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki) (`qpzry9x8gf2tvdw0s3jn54khce6mua7l`)
+5. Produce the final address string: `hrp + "1" + encoded_data`
 
-## Network Parameters
+Decoders MUST reverse these steps and MUST verify:
 
-| Address type | Mainnet version | Expected prefix | Testnet/Devnet/Regtest version | Expected prefix |
-| ------------ | --------------- | --------------- | ------------------------------ | ---------------- |
-| Platform P2PKH | `0x1e` | `D` | `0x5a` | `d` |
-| Platform P2SH | `0x38` | `P` | `0x75` | `p` |
+* Checksum validity (per [BIP-350](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki#appendix-checksum-design--properties)),
+* HRP correctness for the target network,
+* Data-part length requirements,
+* The type byte is either `0x00` or `0x01`.
 
-These prefixes are distinct from Dash Core chain (`X`/`7`/`y`/`8`) and from each other.
+#### Structure
 
-## Validation
+All Platform addresses are encoded as:
 
-An address is valid for a network if:
+```text
+ "1" 
+```
+
+* `` is network-specific (see table).
+* `` contains:
+  * one type byte (`0x00` P2PKH, `0x01` 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](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki#bech32m).
+
+#### 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 and [Bitcoin Cash](https://reference.cash/protocol/blockchain/encoding/cashaddr):
+
+```text
+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 | `dashevo`  |
+| Testnet / Devnet / Regtest | `tdashevo` |
+
+Type byte meaning:
+
+| Address Type   | Type byte |
+| -------------- | --------- |
+| Platform P2PKH | `0x00`    |
+| Platform P2SH  | `0x01`    |
+
+### Validation
+
+A Platform address is valid if:
 
-1. Base58 decoding yields 25 bytes.
-2. The checksum matches the first 4 bytes of `SHA256(SHA256(version || payload))`.
-3. The version byte equals the network’s P2PKH or P2SH Platform prefix.
-4. Wallets MUST reject Platform addresses when constructing Dash Core chain scripts and SHOULD present a clear warning if a user attempts to mix layers.
+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 `0x00` or `0x01`.
 
-## Wallet and Hardware Wallet Behavior
+Wallets MUST reject Platform addresses when constructing Dash 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](dip-0017.md).
 * Wallets MUST use the P2SH encoding for Platform scripts intended to receive Platform funds.
-* Hardware wallets MUST whitelist the version bytes above and display “Dash Platform address” or “Dash Platform script address” as appropriate.
+* 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](dip-0017.md) 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 (`0x00` or `0x01`). Devices MUST display a user-facing descriptor: “Dash Platform address” for P2PKH and “Dash Platform script address” for P2SH.
+
+## Rationale
 
-# Rationale
+Bech32m was chosen over Base58Check because it:
 
-* **Base58Check:** Aligns with existing Dash address UX and reduces user confusion compared to introducing a new encoding.
-* **Distinct prefixes:** `D/d` for P2PKH and `P/p` for P2SH avoid collisions with Core chain addresses and with each other.
-* **Script support:** P2SH enables multisig and policy scripts on Platform without overloading the P2PKH prefix.
+* Improves checksum strength
+* Is QR efficient
+* Avoids ambiguous characters
+* Clearly separates networks using HRPs
+* Future-proofs script or address extensions
 
-# Backwards Compatibility
+## 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](dip-0017.md)) are unchanged.
 
-# Reference Implementation
+## Reference Implementation
+
+Note: The following pseudocode covers the encoding and decoding parts of DIP-18 only, not the wallet-UI or signing device behaviors.
 
 ```text
-function encode_platform_address(payload, type, network):
-    # payload: 20-byte HASH160
+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 = 0x00 if type=="p2pkh" else 0x01 if type=="p2sh" else error()
+
+    hrp = {
+        "mainnet": "dashevo",
+        "testnet": "tdashevo",
+    }.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)
 
-    if type == "p2pkh":
-        version = 0x1e if network == "mainnet" else 0x5a
-    else if type == "p2sh":
-        version = 0x38 if network == "mainnet" else 0x75
+    # Infer network from HRP
+    network = {
+        "dashevo":  "mainnet",
+        "tdashevo": "testnet",
+    }.get(hrp)
+
+    if network is null:
+        error("unknown hrp / network")
+
+    payload = convertbits(data, 5, 8, pad=false)
+    if len(payload) != 21:
+        error("invalid payload length")
+
+    type_byte = payload[0]
+    hash160   = payload[1:21]
+
+    if type_byte == 0x00:
+        addr_type = "p2pkh"
+    else if type_byte == 0x01:
+        addr_type = "p2sh"
     else:
-        error("unknown type")
-
-    data = version || payload
-    checksum = SHA256(SHA256(data))[0:4]
-    return Base58Encode(data || checksum)
-
-function decode_platform_address(addr, network):
-    raw = Base58Decode(addr)
-    assert len(raw) == 25
-    version = raw[0]
-    payload = raw[1:21]
-    checksum = raw[21:25]
-    expect = SHA256(SHA256(raw[0:21]))[0:4]
-    assert checksum == expect
-
-    valid_p2pkh = (version == 0x1e and network == "mainnet") or (version == 0x5a and network != "mainnet")
-    valid_p2sh  = (version == 0x38 and network == "mainnet") or (version == 0x75 and network != "mainnet")
-    assert valid_p2pkh or valid_p2sh
-
-    return payload, ("p2pkh" if valid_p2pkh else "p2sh")
+        error("unknown type byte")
+
+    return network, addr_type, hash160
 ```
 
-# Security Considerations
+A Python implementation is available at [`dip-0018/bech32.py`](dip-0018/bech32.py). It uses the [BIP-350 reference code](https://github.com/sipa/bech32/blob/master/ref/python/segwit_addr.py) by Pieter Wuille and validates against the [provided test vectors](#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 Considerations
 
-* Base58Check addresses are unshielded; privacy relies on HD key rotation per [DIP-17](dip-0017.md) and script hygiene.
+* Privacy relies on HD key rotation per [DIP-17](dip-0017.md) 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
+## Test Vectors
 
 Mnemonic (shared with [DIP-17](dip-0017.md)): `abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about`  
 Passphrase: `""`
 
-## P2PKH examples (payloads from DIP-17)
+The HASH160 payloads in the following tables are derived from the mnemonic and paths specified in [DIP-17](dip-0017.md). Implementations MAY use those derivation vectors to perform end-to-end tests (mnemonic → key → pubkey → HASH160 → address).
+
+### P2PKH examples
+
+| Vector | Payload (HASH160) | Mainnet (`dashevo`) | Testnet (`tdashevo`) |
+| ------ | ------------------------------------------ | ------------------------------------------------ | ------------------------------------------------- |
+| 1      | `f7da0a2b5cbd4ff6bb2c4d89b67d2f3ffeec0525` | `dashevo1qrma5z3ttj75la4m93xcndna9ullamq9y5smxxxm` | `tdashevo1qrma5z3ttj75la4m93xcndna9ullamq9y5aawfeu` |
+| 2      | `a5ff0046217fd1c7d238e3e146cc5bfd90832a7e` | `dashevo1qzjl7qzxy9lar37j8r37z3kvt07epqe20clcut89` | `tdashevo1qzjl7qzxy9lar37j8r37z3kvt07epqe20cj75ycz` |
+| 3      | `6d92674fd64472a3dfcfc3ebcfed7382bf699d7b` | `dashevo1qpkeye606ez89g7lelp7hnldwwpt76va0vcv050v` | `tdashevo1qpkeye606ez89g7lelp7hnldwwpt76va0v428mst` |
 
-| Vector | Path (mainnet / testnet) | account' | key_class' | index | HASH160(pubkey) | Mainnet P2PKH | Testnet P2PKH |
-| ------ | ----------------------- | -------- | ---------- | ----- | --------------- | ------------- | -------------- |
-| 1 | m/9'/5'/17'/0'/0'/0 / m/9'/1'/17'/0'/0'/0 | 0' | 0' | 0 | f7da0a2b5cbd4ff6bb2c4d89b67d2f3ffeec0525 | DTjceJiEqrNkCsSizK65fojEANTKoQMtsR | dSqV2orinasFpYAMGQTLy6uYpW9Dnge563 |
-| 2 | m/9'/5'/17'/0'/0'/1 / m/9'/1'/17'/0'/0'/1 | 0' | 0' | 1 | a5ff0046217fd1c7d238e3e146cc5bfd90832a7e | DLGoWhHfAyFcJafRgt2fFN7fxgLqNrfCXm | dZoepEc46ivSfm3VYr8mJeA4hZXYytgkKZ |
-| 3 | m/9'/5'/17'/0'/1'/0 / m/9'/1'/17'/0'/1'/0 | 0' | 1' | 0 | 6d92674fd64472a3dfcfc3ebcfed7382bf699d7b | DF8TaTy7YrLdGYqq6cwapSUqdM3qJxLQbo | dFQSkGujaeDNwWTQDDVfbrurQ9ChXXYDov |
+### P2SH example
 
-## P2SH example
+Payload: `43fa183cf3fb6e9e7dc62b692aeb4fc8d8045636`
 
-* Script (hex): `76a914000102030405060708090a0b0c0d0e0f101112131488ac` (standard HASH160-to-pubkey script for illustration)
-* HASH160(script): `43fa183cf3fb6e9e7dc62b692aeb4fc8d8045636`
-* Mainnet P2SH: `Pe8D1pMrEnWsmuj5zCEBhHTcsFE51Asp8k`
-* Testnet P2SH: `pBk15SYRYnnKfMENUnYdGw4cG1wcRmSdoh`
+* Mainnet: `dashevo1q9pl5xpu70aka8nacc4kj2htflydspzkxckndrac`
+* Testnet: `tdashevo1q9pl5xpu70aka8nacc4kj2htflydspzkxcm49vzl`
 
-# Copyright
+## Copyright
 
 Copyright (c) 2025 Dash Core Group, Inc. [Licensed under the MIT License](https://opensource.org/licenses/MIT)
diff --git a/dip-0018/bech32.py b/dip-0018/bech32.py
new file mode 100644
index 00000000..6b6477fa
--- /dev/null
+++ b/dip-0018/bech32.py
@@ -0,0 +1,467 @@
+#!/usr/bin/env python3
+# Copyright (c) 2017, 2020 Pieter Wuille
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+"""
+DIP-18 Bech32m address encoding for Dash Platform, with full DIP-17 test vector validation.
+
+Bech32/Bech32m functions are copied verbatim from BIP-350 reference implementation:
+https://github.com/sipa/bech32/blob/master/ref/python/segwit_addr.py
+
+This module provides:
+- Bech32m encoding/decoding (BIP-350)
+- Dash Platform address encoding/decoding (DIP-18)
+- BIP-39/BIP-32 derivation for validating DIP-17 test vectors
+
+Dependencies:
+    pip install ecdsa
+
+Usage:
+    python bech32.py
+"""
+
+from typing import Tuple, Literal
+from hashlib import sha256, pbkdf2_hmac
+from enum import Enum
+import hashlib
+import hmac
+import unicodedata
+
+from ecdsa import SECP256k1, SigningKey
+
+# ---- Bech32/Bech32m reference implementation (BIP-350) ----
+# The following code up to "End of BIP-350 reference" is copied verbatim from:
+# https://github.com/sipa/bech32/blob/master/ref/python/segwit_addr.py
+
+
+class Encoding(Enum):
+    """Enumeration type to list the various supported encodings."""
+    BECH32 = 1
+    BECH32M = 2
+
+CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
+BECH32M_CONST = 0x2bc830a3
+
+def bech32_polymod(values):
+    """Internal function that computes the Bech32 checksum."""
+    generator = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]
+    chk = 1
+    for value in values:
+        top = chk >> 25
+        chk = (chk & 0x1ffffff) << 5 ^ value
+        for i in range(5):
+            chk ^= generator[i] if ((top >> i) & 1) else 0
+    return chk
+
+
+def bech32_hrp_expand(hrp):
+    """Expand the HRP into values for checksum computation."""
+    return [ord(x) >> 5 for x in hrp] + [0] + [ord(x) & 31 for x in hrp]
+
+
+def bech32_verify_checksum(hrp, data):
+    """Verify a checksum given HRP and converted data characters."""
+    const = bech32_polymod(bech32_hrp_expand(hrp) + data)
+    if const == 1:
+        return Encoding.BECH32
+    if const == BECH32M_CONST:
+        return Encoding.BECH32M
+    return None
+
+def bech32_create_checksum(hrp, data, spec):
+    """Compute the checksum values given HRP and data."""
+    values = bech32_hrp_expand(hrp) + data
+    const = BECH32M_CONST if spec == Encoding.BECH32M else 1
+    polymod = bech32_polymod(values + [0, 0, 0, 0, 0, 0]) ^ const
+    return [(polymod >> 5 * (5 - i)) & 31 for i in range(6)]
+
+
+def bech32_encode(hrp, data, spec):
+    """Compute a Bech32 string given HRP and data values."""
+    combined = data + bech32_create_checksum(hrp, data, spec)
+    return hrp + '1' + ''.join([CHARSET[d] for d in combined])
+
+def bech32_decode(bech):
+    """Validate a Bech32/Bech32m string, and determine HRP and data."""
+    if ((any(ord(x) < 33 or ord(x) > 126 for x in bech)) or
+            (bech.lower() != bech and bech.upper() != bech)):
+        return (None, None, None)
+    bech = bech.lower()
+    pos = bech.rfind('1')
+    if pos < 1 or pos + 7 > len(bech) or len(bech) > 90:
+        return (None, None, None)
+    if not all(x in CHARSET for x in bech[pos+1:]):
+        return (None, None, None)
+    hrp = bech[:pos]
+    data = [CHARSET.find(x) for x in bech[pos+1:]]
+    spec = bech32_verify_checksum(hrp, data)
+    if spec is None:
+        return (None, None, None)
+    return (hrp, data[:-6], spec)
+
+def convertbits(data, frombits, tobits, pad=True):
+    """General power-of-2 base conversion."""
+    acc = 0
+    bits = 0
+    ret = []
+    maxv = (1 << tobits) - 1
+    max_acc = (1 << (frombits + tobits - 1)) - 1
+    for value in data:
+        if value < 0 or (value >> frombits):
+            return None
+        acc = ((acc << frombits) | value) & max_acc
+        bits += frombits
+        while bits >= tobits:
+            bits -= tobits
+            ret.append((acc >> bits) & maxv)
+    if pad:
+        if bits:
+            ret.append((acc << (tobits - bits)) & maxv)
+    elif bits >= frombits or ((acc << (tobits - bits)) & maxv):
+        return None
+    return ret
+
+
+# ---- End of BIP-350 reference ----
+
+
+# ---- Dash Platform address encoding on top of Bech32m ----
+
+Network = Literal["mainnet", "testnet"]
+AddrType = Literal["p2pkh", "p2sh"]
+
+NETWORK_TO_HRP = {
+    "mainnet": "dashevo",
+    "testnet": "tdashevo"
+}
+
+HRP_TO_NETWORK = {v: k for k, v in NETWORK_TO_HRP.items()}
+
+TYPE_TO_BYTE = {
+    "p2pkh": 0x00,
+    "p2sh": 0x01,
+}
+
+BYTE_TO_TYPE = {v: k for k, v in TYPE_TO_BYTE.items()}
+
+
+def encode_platform_address(hash160: bytes,
+                            addr_type: AddrType,
+                            network: Network) -> str:
+    """
+    Encode a Dash Platform address as Bech32m.
+
+    :param hash160: 20-byte HASH160(pubkey or script)
+    :param addr_type: "p2pkh" or "p2sh"
+    :param network: "mainnet", "testnet"
+    :return: Bech32m-encoded address string
+    """
+    if len(hash160) != 20:
+        raise ValueError("hash160 must be 20 bytes")
+
+    if addr_type not in TYPE_TO_BYTE:
+        raise ValueError("unknown addr_type")
+
+    if network not in NETWORK_TO_HRP:
+        raise ValueError("unknown network")
+
+    hrp = NETWORK_TO_HRP[network]
+    type_byte = TYPE_TO_BYTE[addr_type]
+
+    payload_bytes = bytes([type_byte]) + hash160  # 21 bytes
+    data5 = convertbits(payload_bytes, 8, 5, pad=True)
+
+    return bech32_encode(hrp, data5, Encoding.BECH32M)
+
+
+def decode_platform_address(addr: str) -> Tuple[Network, AddrType, bytes]:
+    """
+    Decode a Dash Platform Bech32m address into (network, addr_type, hash160).
+
+    :param addr: Bech32m-encoded Dash Platform address
+    :return: (network, "p2pkh"/"p2sh", 20-byte hash160)
+    """
+    hrp, data_no_checksum, spec = bech32_decode(addr)
+
+    if hrp is None:
+        raise ValueError("invalid Bech32m address")
+
+    if spec != Encoding.BECH32M:
+        raise ValueError("address is not Bech32m encoded")
+
+    if hrp not in HRP_TO_NETWORK:
+        raise ValueError(f"unknown HRP '{hrp}' for Dash Platform")
+
+    network = HRP_TO_NETWORK[hrp]
+
+    # Convert back to 8-bit payload, without padding
+    payload_bytes = convertbits(data_no_checksum, 5, 8, pad=False)
+    if payload_bytes is None:
+        raise ValueError("invalid payload encoding")
+    payload_bytes = bytes(payload_bytes)
+
+    if len(payload_bytes) != 21:
+        raise ValueError("invalid payload length (expected 21 bytes)")
+
+    type_byte = payload_bytes[0]
+    hash160 = payload_bytes[1:]
+
+    if type_byte not in BYTE_TO_TYPE:
+        raise ValueError(f"unknown type byte {type_byte:#x}")
+
+    addr_type = BYTE_TO_TYPE[type_byte]
+
+    return network, addr_type, hash160
+
+
+# ---- BIP-39 / BIP-32 derivation for test vector validation ----
+
+# Hardened flag for BIP-32 derivation
+H = 0x80000000
+
+
+def mnemonic_to_seed(mnemonic: str, passphrase: str = "") -> bytes:
+    """BIP-39: Convert mnemonic to 64-byte seed using PBKDF2-HMAC-SHA512."""
+    mnemonic = unicodedata.normalize('NFKD', mnemonic)
+    passphrase = unicodedata.normalize('NFKD', passphrase)
+    return pbkdf2_hmac(
+        "sha512",
+        mnemonic.encode("utf-8"),
+        ("mnemonic" + passphrase).encode("utf-8"),
+        2048
+    )
+
+
+def bip32_master(seed: bytes) -> tuple[bytes, bytes]:
+    """BIP-32: Derive master private key and chain code from seed."""
+    I = hmac.new(b"Bitcoin seed", seed, "sha512").digest()
+    return I[:32], I[32:]  # private_key, chain_code
+
+
+def bip32_derive_child(priv_key: bytes, chain_code: bytes, index: int) -> tuple[bytes, bytes]:
+    """BIP-32: Derive child key at given index (hardened if index >= 0x80000000)."""
+    if index >= 0x80000000:  # hardened
+        data = b'\x00' + priv_key + index.to_bytes(4, 'big')
+    else:  # normal
+        sk = SigningKey.from_string(priv_key, curve=SECP256k1)
+        pubkey = sk.get_verifying_key().to_string("compressed")
+        data = pubkey + index.to_bytes(4, 'big')
+
+    I = hmac.new(chain_code, data, "sha512").digest()
+    child_key_int = (int.from_bytes(I[:32], 'big') + int.from_bytes(priv_key, 'big')) % SECP256k1.order
+    return child_key_int.to_bytes(32, 'big'), I[32:]
+
+
+def derive_path(seed: bytes, path: list[int]) -> bytes:
+    """Derive private key at full BIP-32 path."""
+    priv, chain = bip32_master(seed)
+    for idx in path:
+        priv, chain = bip32_derive_child(priv, chain, idx)
+    return priv
+
+
+def hash160(data: bytes) -> bytes:
+    """HASH160 = RIPEMD160(SHA256(data))."""
+    return hashlib.new('ripemd160', sha256(data).digest()).digest()
+
+
+def priv_to_compressed_pub(priv_key: bytes) -> bytes:
+    """Convert private key to compressed public key (33 bytes)."""
+    sk = SigningKey.from_string(priv_key, curve=SECP256k1)
+    return sk.get_verifying_key().to_string("compressed")
+
+
+def format_path(path: list[int]) -> str:
+    """Format derivation path for display."""
+    parts = ["m"]
+    for idx in path:
+        if idx >= H:
+            parts.append(f"{idx - H}'")
+        else:
+            parts.append(str(idx))
+    return "/".join(parts)
+
+
+# ---- Test vectors ----
+
+# DIP-17 P2PKH vectors: (path, priv_hex, pub_hex, hash160_hex, mainnet_addr, testnet_addr)
+DIP17_VECTORS = [
+    # Vector 1: m/9'/5'/17'/0'/0'/0
+    (
+        [9 + H, 5 + H, 17 + H, 0 + H, 0 + H, 0],
+        "6bca392f43453b7bc33a9532b69221ce74906a8815281637e0c9d0bee35361fe",
+        "03de102ed1fc43cbdb16af02e294945ffaed8e0595d3072f4c592ae80816e6859e",
+        "f7da0a2b5cbd4ff6bb2c4d89b67d2f3ffeec0525",
+        "dashevo1qrma5z3ttj75la4m93xcndna9ullamq9y5smxxxm",
+        "tdashevo1qrma5z3ttj75la4m93xcndna9ullamq9y5aawfeu",
+    ),
+    # Vector 2: m/9'/5'/17'/0'/0'/1
+    (
+        [9 + H, 5 + H, 17 + H, 0 + H, 0 + H, 1],
+        "eef58ce73383f63d5062f281ed0c1e192693c170fbc0049662a73e48a1981523",
+        "02269ff766fcd04184bc314f5385a04498df215ce1e7193cec9a607f69bc8954da",
+        "a5ff0046217fd1c7d238e3e146cc5bfd90832a7e",
+        "dashevo1qzjl7qzxy9lar37j8r37z3kvt07epqe20clcut89",
+        "tdashevo1qzjl7qzxy9lar37j8r37z3kvt07epqe20cj75ycz",
+    ),
+    # Vector 3: m/9'/5'/17'/0'/1'/0 (key_class' = 1')
+    (
+        [9 + H, 5 + H, 17 + H, 0 + H, 1 + H, 0],
+        "cc05b4389712a2e724566914c256217685d781503d7cc05af6642e60260830db",
+        "0317a3ed70c141cffafe00fa8bf458cec119f6fc039a7ba9a6b7303dc65b27bed3",
+        "6d92674fd64472a3dfcfc3ebcfed7382bf699d7b",
+        "dashevo1qpkeye606ez89g7lelp7hnldwwpt76va0vcv050v",
+        "tdashevo1qpkeye606ez89g7lelp7hnldwwpt76va0v428mst",
+    ),
+]
+
+# DIP-18 P2SH vector (address encoding only, no derivation path)
+P2SH_VECTOR = (
+    "43fa183cf3fb6e9e7dc62b692aeb4fc8d8045636",
+    "dashevo1q9pl5xpu70aka8nacc4kj2htflydspzkxckndrac",
+    "tdashevo1q9pl5xpu70aka8nacc4kj2htflydspzkxcm49vzl",
+)
+
+
+# ---- Self-test ----
+
+if __name__ == "__main__":
+    print("=" * 70)
+    print("DIP-17 / DIP-18 Test Vector Validation")
+    print("=" * 70)
+
+    # BIP-39 mnemonic (test-only)
+    mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
+    passphrase = ""
+
+    print(f"\nMnemonic: {mnemonic}")
+    print(f"Passphrase: {'(empty)' if not passphrase else passphrase}")
+
+    # Step 1: Mnemonic to seed
+    seed = mnemonic_to_seed(mnemonic, passphrase)
+    print(f"Seed: {seed.hex()}")
+
+    all_passed = True
+
+    # Step 2: Validate DIP-17 derivation vectors
+    print("\n" + "-" * 70)
+    print("DIP-17 Derivation Validation")
+    print("-" * 70)
+
+    for i, (path, expected_priv, expected_pub, expected_hash, _, _) in enumerate(DIP17_VECTORS, 1):
+        print(f"\nVector {i}: {format_path(path)}")
+
+        # Derive private key
+        priv = derive_path(seed, path)
+        priv_hex = priv.hex()
+
+        # Derive public key
+        pub = priv_to_compressed_pub(priv)
+        pub_hex = pub.hex()
+
+        # Compute HASH160
+        h160 = hash160(pub)
+        h160_hex = h160.hex()
+
+        # Validate
+        priv_ok = priv_hex == expected_priv
+        pub_ok = pub_hex == expected_pub
+        hash_ok = h160_hex == expected_hash
+
+        print(f"  Private Key: {priv_hex}")
+        print(f"    Expected:  {expected_priv} {'✓' if priv_ok else '✗ MISMATCH'}")
+
+        print(f"  Public Key:  {pub_hex}")
+        print(f"    Expected:  {expected_pub} {'✓' if pub_ok else '✗ MISMATCH'}")
+
+        print(f"  HASH160:     {h160_hex}")
+        print(f"    Expected:  {expected_hash} {'✓' if hash_ok else '✗ MISMATCH'}")
+
+        if not (priv_ok and pub_ok and hash_ok):
+            all_passed = False
+
+    # Step 3: Validate DIP-18 P2PKH address encoding
+    print("\n" + "-" * 70)
+    print("DIP-18 P2PKH Address Encoding Validation")
+    print("-" * 70)
+
+    for i, (_, _, _, expected_hash, expected_main, expected_test) in enumerate(DIP17_VECTORS, 1):
+        h160 = bytes.fromhex(expected_hash)
+
+        mainnet_addr = encode_platform_address(h160, "p2pkh", "mainnet")
+        testnet_addr = encode_platform_address(h160, "p2pkh", "testnet")
+
+        main_ok = mainnet_addr == expected_main
+        test_ok = testnet_addr == expected_test
+
+        print(f"\nVector {i} (HASH160: {expected_hash[:16]}...):")
+        print(f"  Mainnet: {mainnet_addr}")
+        print(f"    Expected: {expected_main} {'✓' if main_ok else '✗ MISMATCH'}")
+        print(f"  Testnet: {testnet_addr}")
+        print(f"    Expected: {expected_test} {'✓' if test_ok else '✗ MISMATCH'}")
+
+        # Verify round-trip decoding
+        dec_net_m, dec_type_m, dec_hash_m = decode_platform_address(mainnet_addr)
+        dec_net_t, dec_type_t, dec_hash_t = decode_platform_address(testnet_addr)
+
+        assert dec_net_m == "mainnet" and dec_type_m == "p2pkh" and dec_hash_m.hex() == expected_hash
+        assert dec_net_t == "testnet" and dec_type_t == "p2pkh" and dec_hash_t.hex() == expected_hash
+
+        if not (main_ok and test_ok):
+            all_passed = False
+
+    # Step 4: Validate DIP-18 P2SH address encoding
+    print("\n" + "-" * 70)
+    print("DIP-18 P2SH Address Encoding Validation")
+    print("-" * 70)
+
+    p2sh_hash, p2sh_main_expected, p2sh_test_expected = P2SH_VECTOR
+    h160 = bytes.fromhex(p2sh_hash)
+
+    mainnet_addr = encode_platform_address(h160, "p2sh", "mainnet")
+    testnet_addr = encode_platform_address(h160, "p2sh", "testnet")
+
+    main_ok = mainnet_addr == p2sh_main_expected
+    test_ok = testnet_addr == p2sh_test_expected
+
+    print(f"\nP2SH (HASH160: {p2sh_hash[:16]}...):")
+    print(f"  Mainnet: {mainnet_addr}")
+    print(f"    Expected: {p2sh_main_expected} {'✓' if main_ok else '✗ MISMATCH'}")
+    print(f"  Testnet: {testnet_addr}")
+    print(f"    Expected: {p2sh_test_expected} {'✓' if test_ok else '✗ MISMATCH'}")
+
+    # Verify round-trip decoding
+    dec_net_m, dec_type_m, dec_hash_m = decode_platform_address(mainnet_addr)
+    dec_net_t, dec_type_t, dec_hash_t = decode_platform_address(testnet_addr)
+
+    assert dec_net_m == "mainnet" and dec_type_m == "p2sh" and dec_hash_m.hex() == p2sh_hash
+    assert dec_net_t == "testnet" and dec_type_t == "p2sh" and dec_hash_t.hex() == p2sh_hash
+
+    if not (main_ok and test_ok):
+        all_passed = False
+
+    # Summary
+    print("\n" + "=" * 70)
+    if all_passed:
+        print("✓ All test vectors validated successfully!")
+    else:
+        print("✗ Some test vectors failed validation!")
+        exit(1)
+    print("=" * 70)

From fd319d50a38e8a8b791026f8b74f74e50c8edc5c Mon Sep 17 00:00:00 2001
From: thephez 
Date: Thu, 11 Dec 2025 16:06:03 -0500
Subject: [PATCH 6/7] chore: formatting and minor updates

---
 dip-0017.md | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/dip-0017.md b/dip-0017.md
index 21ce16dd..fe7899d6 100644
--- a/dip-0017.md
+++ b/dip-0017.md
@@ -30,15 +30,15 @@
 1. [DIP-9 Registry Update](#dip-9-registry-update)
 1. [Copyright](#copyright)
 
-# Abstract
+## Abstract
 
-This DIP defines Dash Platform payment addresses (“D-addresses”) and their hierarchical deterministic (HD) derivation under [DIP-9](dip-0009.md). It uses Dash coin type 5' on mainnet and coin type 1' on test networks, and introduces a new [DIP-9](dip-0009.md) feature index for Platform payments. The specification standardizes derivation paths (including account separation) and wallet/hardware wallet guidance for Platform payment keys. Address encoding (version bytes and formats) and script-hash address formats are defined in [DIP-18](dip-0018.md).
+This DIP defines Dash Platform payment addresses and their hierarchical deterministic (HD) derivation under [DIP-9](dip-0009.md). It uses Dash coin type 5' on mainnet and coin type 1' on test networks, and introduces a new [DIP-9](dip-0009.md) feature index for Platform payments. The specification standardizes derivation paths (including account separation) and wallet/hardware wallet guidance for Platform payment keys. Address encoding (version bytes and formats) and script-hash address formats are defined in [DIP-18](dip-0018.md).
 
-# Motivation
+## Motivation
 
 Dash Platform enables value transfers distinct from Dash Core chain UTXO transactions. Wallets require an unambiguous address type, network-specific encodings, and deterministic derivation paths that coexist with BIP-44 Core chain funds and existing [DIP-9](dip-0009.md) features (masternodes, identities, DashPay). This DIP provides a single standard so wallets, hardware wallets, and services can implement Platform payments.
 
-# Prior Work
+## Prior Work
 
 * [DIP-0009: Feature Derivation Paths](https://github.com/dashpay/dips/blob/master/dip-0009.md)
 * [DIP-0013: Identities in Hierarchical Deterministic Wallets](https://github.com/dashpay/dips/blob/master/dip-0013.md)
@@ -46,13 +46,13 @@ Dash Platform enables value transfers distinct from Dash Core chain UTXO transac
 * [BIP-0032: Hierarchical Deterministic Wallets](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki)
 * [BIP-0044: Multi-Account Hierarchy for Deterministic Wallets](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)
 
-# Specification
+## Specification
 
-## Overview
+### Overview
 
 Platform payment keys identify recipients of value on Dash Platform. This value includes Dash Credits, which represent DASH held on Platform, as well as other Platform-based payments. These keys are independent of Dash Platform identities and do not belong to an identity’s key set. Instead, they function as standalone payment keys that hold value outside of any identity. They use a single secp256k1 key pair and are not script-based. They are not valid Dash Core chain addresses and MUST NOT be used for Core chain transactions. Their encoding format is specified in [DIP-18](dip-0018.md).
 
-## Derivation Path Definition
+### Derivation Path Definition
 
 The Platform payment feature is assigned [DIP-9](dip-0009.md) feature index `17'`. The canonical derivation path is:
 
@@ -81,7 +81,7 @@ Wallets MAY derive and expose an extended public key at `m/9'/5'/17'/account'/ke
 
 Accounts follow BIP-44 semantics: `account'` partitions user-controlled sets of Platform payment keys, enabling multiple profiles or organizational separations while preserving hardened isolation between accounts.
 
-## Wallet and Hardware Wallet Behavior
+### Wallet and Hardware Wallet Behavior
 
 * Wallets MUST derive Platform payment keys only from `m/9'/5'/17'/account'/key_class'/index` (mainnet) or `m/9'/1'/17'/account'/key_class'/index` (test networks). Address encoding of the resulting public keys is specified in [DIP-18](dip-0018.md).
 * Wallets SHOULD clearly separate Platform chain balances from Core chain balances in UI and storage.
@@ -92,7 +92,7 @@ Accounts follow BIP-44 semantics: `account'` partitions user-controlled sets of
 * Hardware wallets MUST apply the address encodings defined in [DIP-18](dip-0018.md) and MUST NOT reinterpret these as Core chain P2PKH/P2SH.
 * If a wallet does not implement Platform, it simply never derives the `17'` feature path.
 
-# Rationale
+## Rationale
 
 * **Coin type 5' on mainnet, 1' on test networks:** Mainnet keeps Dash SLIP-44 coin type 5', while testnet/devnet/regtest follow SLIP-44 convention with coin type 1'. This avoids new registry allocations and keeps all Dash features under the established namespaces.
 * **DIP-9 vs BIP-44:** DIP-9’s feature level cleanly separates Platform addresses from Core chain funds and from identities/masternodes without overloading BIP-44’s change level or accounts.
@@ -102,9 +102,9 @@ Accounts follow BIP-44 semantics: `account'` partitions user-controlled sets of
 * **Accounts retained:** A hardened `account'` level maintains BIP-44-style multi-account semantics while still isolating Platform keys under the [DIP-9](dip-0009.md) feature branch.
 * **No BIP-44 change level:** Platform addresses are not UTXO change outputs; a linear `index` (optionally partitioned by `key_class'`) keeps the model simple for hardware wallets and avoids misuse of the 0/1 change bit.
 
-# Backwards Compatibility
+## Backwards Compatibility
 
-* Classic Dash addresses (`X...`, `7...`, `y...`, `8...`) are unaffected. Nodes do not accept D-addresses in Core chain scripts.
+* Classic Dash addresses (`X...`, `7...`, `y...`, `8...`) are unaffected. Nodes do not accept Platform addresses in Core chain scripts.
 * DIP-[3](dip-0003.md)/[8](dip-0008.md) masternode derivations and [DIP-13](dip-0013.md) identity derivations remain unchanged.
 * Existing seeds stay valid; wallets can add Platform support without migration.
 * Wallets unaware of Platform will not derive `m/9'/5'/17'/...` and therefore will not interfere with Platform balances.
@@ -139,21 +139,21 @@ function platform_payment_key(seed, account, key_class, index, network):
 
 Encoding and decoding of these payloads into addresses is specified in [DIP-18](dip-0018.md).
 
-# Security Considerations
+## Security Considerations
 
 * Derivation uses hardened separation at `feature'` and `key_class'`; compromise of a Platform xpub does not expose other features or other key classes.
 * Leakage of the xpub at `m/9'/coin_type'/17'/account'/key_class'` allows derivation of all Platform public keys for that key class but does not leak private keys or other features.
-* Wallets MUST reject attempts to use D-addresses in Core chain transactions to prevent misdirected funds.
+* Wallets MUST reject attempts to use Platform addresses in Core chain transactions to prevent misdirected funds.
 * Hardware wallets MUST show the full derivation path and “Dash Platform address” to reduce key-path confusion attacks.
 * The checksum and distinct prefixes mitigate accidental prefix confusion with `X`/`7`/`y`/`8` addresses.
 
-# Privacy Considerations
+## Privacy Considerations
 
 * Wallets SHOULD avoid address reuse by incrementing `index` and MAY use separate `key_class'` values to segregate user profiles or accounts.
 * Wallets SHOULD avoid correlating Platform `index` progression with Core chain BIP-44 indices to reduce cross-layer linkability.
 * Sharing xpubs at `m/9'/coin_type'/17'/account'/key_class'` enables watch-only but also enables address graph reconstruction for that class; applications should only share when necessary.
 
-# Test Vectors
+## Test Vectors
 
 Mnemonic (test-only): `abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about`  
 Passphrase: `""` (empty)
@@ -166,7 +166,7 @@ All hex strings are lowercase, big-endian. Address encodings for the HASH160 val
 | 2 | m/9'/5'/17'/0'/0'/1 (mainnet) / m/9'/1'/17'/0'/0'/1 (test) | 0' | 0' | 1 | eef58ce73383f63d5062f281ed0c1e192693c170fbc0049662a73e48a1981523 | 02269ff766fcd04184bc314f5385a04498df215ce1e7193cec9a607f69bc8954da | a5ff0046217fd1c7d238e3e146cc5bfd90832a7e |
 | 3 (non-default class) | m/9'/5'/17'/0'/1'/0 (mainnet) / m/9'/1'/17'/0'/1'/0 (test) | 0' | 1' | 0 | cc05b4389712a2e724566914c256217685d781503d7cc05af6642e60260830db | 0317a3ed70c141cffafe00fa8bf458cec119f6fc039a7ba9a6b7303dc65b27bed3 | 6d92674fd64472a3dfcfc3ebcfed7382bf699d7b |
 
-# DIP-9 Registry Update
+## DIP-9 Registry Update
 
 Reserve [DIP-9](dip-0009.md) feature index `17'` for “Platform Payment Addresses”:
 
@@ -174,6 +174,6 @@ Reserve [DIP-9](dip-0009.md) feature index `17'` for “Platform Payment Address
 | ------------- | ------- | --- | ---- |
 | `17'` | Platform Payment Addresses | DIP-17 | Sub-path: `17'/account'/key_class'/index` (default account' = `0'`, key_class' = `0'`) |
 
-# Copyright
+## Copyright
 
 Copyright (c) 2025 Dash Core Group, Inc. [Licensed under the MIT License](https://opensource.org/licenses/MIT)

From 3eac6fca586842be6a21d01e0369d0fc7d38a14e Mon Sep 17 00:00:00 2001
From: thephez 
Date: Thu, 11 Dec 2025 16:28:02 -0500
Subject: [PATCH 7/7] docs(dip17): expand motivation per review comment

---
 dip-0017.md | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/dip-0017.md b/dip-0017.md
index fe7899d6..899b6e10 100644
--- a/dip-0017.md
+++ b/dip-0017.md
@@ -36,7 +36,13 @@ This DIP defines Dash Platform payment addresses and their hierarchical determin
 
 ## Motivation
 
-Dash Platform enables value transfers distinct from Dash Core chain UTXO transactions. Wallets require an unambiguous address type, network-specific encodings, and deterministic derivation paths that coexist with BIP-44 Core chain funds and existing [DIP-9](dip-0009.md) features (masternodes, identities, DashPay). This DIP provides a single standard so wallets, hardware wallets, and services can implement Platform payments.
+While Dash Platform identities can hold balances, identity-to-identity payments alone cannot satisfy the requirements for value transfer on Platform. Identities are designed to be persistent, publicly linkable entities with DPNS names and associated documents. Transferring value directly between identities permanently links those identities on-chain, which is undesirable for common payment scenarios and prevents future improvements to privacy and fungibility.
+
+Identity-based transfers also make onboarding unnecessarily complex. Creating a new identity requires funding an asset-lock transaction on the Core chain before the identity can be registered. With a Platform-level payment mechanism, an existing user can send value directly to an address controlled by a new user, allowing that user to create or top up an identity entirely within Platform.
+
+Additionally, many use cases require value that is not tied to a persistent identity—such as one-time payment targets, merchant invoices, or exchange integrations. Platform payment addresses provide this flexibility in a manner analogous to Core-chain addresses.
+
+For these reasons, DIP-17 introduces an address subsystem that complements identity balances and enables direct value transfer, simplified onboarding, improved privacy, and broader application support within Dash Platform. Wallets require an unambiguous address type, network-specific encodings, and deterministic derivation paths that coexist with BIP-44 Core chain funds and existing [DIP-9](dip-0009.md) features (masternodes, identities, DashPay). This DIP defines a single standard so wallets, hardware wallets, and services can implement Platform payments.
 
 ## Prior Work