You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(dip-18): add distinct type byte prefixes (#176)
* feat(dip-18): use type bytes 0xb0/0x80 for P2PKH/P2SH
Change type bytes to produce distinct address prefixes:
- P2PKH: 0xb0 -> addresses start with "k"
- P2SH: 0x80 -> addresses start with "s"
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(dip-18): document type byte visual identification and reserved ranges
- Explain why type byte values were chosen
- Add reserved type byte ranges to prevent future collisions
- Add type_byte_calc.py utility for finding type bytes that map to desired characters
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
@@ -89,7 +89,7 @@ All Platform addresses are encoded as:
89
89
90
90
*`<HRP>` is network-specific (see table).
91
91
*`<data-part>` contains:
92
-
* one type byte (`0x00` P2PKH, `0x01` P2SH), followed by
92
+
* one type byte (`0xb0` P2PKH, `0x80` P2SH), followed by
93
93
* 20-byte HASH160 payload encoded as 5-bit groups via bech32 rules.
94
94
95
95
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).
@@ -120,10 +120,28 @@ The following values define the canonical human-readable prefixes (HRPs) and typ
120
120
121
121
Type byte meaning:
122
122
123
-
| Address Type | Type byte |
124
-
| -------------- | --------- |
125
-
| Platform P2PKH |`0x00`|
126
-
| Platform P2SH |`0x01`|
123
+
| Address Type | Type byte | First data character |
The type bytes `0xb0` and `0x80` were specifically chosen so that the first character after the `1` separator is always `k` for P2PKH and `s` for P2SH. This provides immediate visual identification of address type:
129
+
130
+
* P2PKH addresses always match pattern `evo1k...` (mainnet) or `tevo1k...` (testnet)
131
+
* P2SH addresses always match pattern `evo1s...` (mainnet) or `tevo1s...` (testnet)
132
+
133
+
This mapping is guaranteed because the bech32 `convertbits()` function deterministically converts the first 5 bits of the type byte to the first data character. The high 5 bits of `0xb0` (binary `10110...`) map to index 22 in the bech32 alphabet (`k`), while the high 5 bits of `0x80` (binary `10000...`) map to index 16 (`s`).
134
+
135
+
#### Reserved Type Byte Ranges
136
+
137
+
To preserve visual identification, future address types MUST NOT reuse the first-character mappings of existing types. The first data character is determined by the high 5 bits of the type byte:
138
+
139
+
| High 5 bits | First char | Reserved for | Type byte range |
Future address types SHOULD select type bytes that produce unique first characters not already in use. The reference script [`dip-0018/type_byte_calc.py`](dip-0018/type_byte_calc.py) can be used to find type bytes that map to a desired character.
127
145
128
146
### Validation
129
147
@@ -133,7 +151,7 @@ A Platform address is valid if:
133
151
2. HRP matches expected network.
134
152
3. bech32m checksum verifies.
135
153
4. Payload decodes to exactly 21 bytes.
136
-
5.`payload[0]` is `0x00` or `0x01`.
154
+
5.`payload[0]` is `0xb0` or `0x80`.
137
155
138
156
Wallets MUST reject Platform addresses when constructing Dash Core chain scripts and SHOULD present a clear warning if a user attempts to mix layers.
139
157
@@ -144,10 +162,12 @@ Wallets MUST reject Platform addresses when constructing Dash Core chain scripts
144
162
* Wallets MUST treat HRP as the network selector.
145
163
* Software wallets SHOULD label Platform balances separately from Core chain balances and SHOULD avoid auto-pasting Platform addresses into Core chain contexts.
146
164
* Wallets SHOULD derive payloads via [DIP-17](dip-0017.md) and then encode using these rules; no alternative prefixes are allowed.
147
-
* 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.
165
+
* Hardware wallets MUST validate the HRP to confirm network identity and MUST enforce the type byte (`0xb0` or `0x80`). Devices MUST display a user-facing descriptor: “Dash Platform address” for P2PKH and “Dash Platform script address” for P2SH.
148
166
149
167
## Rationale
150
168
169
+
### Why Bech32m?
170
+
151
171
Bech32m was chosen over Base58Check because it:
152
172
153
173
* Improves checksum strength
@@ -156,6 +176,14 @@ Bech32m was chosen over Base58Check because it:
156
176
* Clearly separates networks using HRPs
157
177
* Future-proofs script or address extensions
158
178
179
+
### Why a Type Byte?
180
+
181
+
Platform addresses embed a type byte as the first byte of the payload. This approach was chosen because:
182
+
183
+
* Platform addresses distinguish between *address types* (P2PKH vs P2SH) for wallet display purposes, not script interpretation versions for consensus (e.g., P2WPKH/P2WSH vs Taproot in Bitcoin). Both address types use identical HASH160 payloads with the same cryptographic properties.
184
+
* A full byte in the payload is straightforward to encode and decode without special handling separate from the hash data.
185
+
* Specific type byte values improve human identification of address type by guaranteeing that P2PKH and P2SH addresses have a unique starting characters.
186
+
159
187
## Backwards Compatibility
160
188
161
189
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.
@@ -171,7 +199,7 @@ function encode_platform_address(hash160, type, network):
171
199
if len(hash160) != 20:
172
200
error("invalid hash160 length")
173
201
174
-
type_byte = 0x00 if type=="p2pkh" else 0x01 if type=="p2sh" else error()
202
+
type_byte = 0xb0 if type=="p2pkh" else 0x80 if type=="p2sh" else error()
175
203
176
204
hrp = {
177
205
"mainnet": "evo",
@@ -209,9 +237,9 @@ function decode_platform_address(addr):
209
237
type_byte = payload[0]
210
238
hash160 = payload[1:21]
211
239
212
-
if type_byte == 0x00:
240
+
if type_byte == 0xb0:
213
241
addr_type = "p2pkh"
214
-
else if type_byte == 0x01:
242
+
else if type_byte == 0x80:
215
243
addr_type = "p2sh"
216
244
else:
217
245
error("unknown type byte")
@@ -243,16 +271,16 @@ The HASH160 payloads in the following tables are derived from the mnemonic and p
0 commit comments