@@ -99,43 +99,54 @@ def convertbits(data, frombits, tobits, pad=True):
9999 return ret
100100
101101
102- def decode_segwit_address (hrp , addr ):
103- """Decode a segwit address."""
102+ DIP18_TYPE_P2PKH = 0xb0
103+ DIP18_TYPE_P2SH = 0x80
104+
105+
106+ def encode_platform_p2pkh (hrp , keyhash ):
107+ """Encode a 20-byte keyhash as a DIP-18 Platform P2PKH bech32m address."""
108+ assert len (keyhash ) == 20
109+ payload = [DIP18_TYPE_P2PKH ] + list (keyhash )
110+ data = convertbits (payload , 8 , 5 )
111+ return bech32_encode (Encoding .BECH32M , hrp , data )
112+
113+
114+ def encode_platform_p2sh (hrp , scripthash ):
115+ """Encode a 20-byte scripthash as a DIP-18 Platform P2SH bech32m address."""
116+ assert len (scripthash ) == 20
117+ payload = [DIP18_TYPE_P2SH ] + list (scripthash )
118+ data = convertbits (payload , 8 , 5 )
119+ return bech32_encode (Encoding .BECH32M , hrp , data )
120+
121+
122+ def decode_platform_address (hrp , addr ):
123+ """Decode a DIP-18 bech32m platform address. Returns (type_byte, hash_bytes) or (None, None)."""
104124 encoding , hrpgot , data = bech32_decode (addr )
105- if hrpgot != hrp :
125+ if encoding != Encoding . BECH32M or hrpgot != hrp :
106126 return (None , None )
107- decoded = convertbits (data [ 1 :] , 5 , 8 , False )
108- if decoded is None or len (decoded ) < 2 or len ( decoded ) > 40 :
127+ payload = convertbits (data , 5 , 8 , pad = False )
128+ if payload is None or len (payload ) != 21 :
109129 return (None , None )
110- if data [0 ] > 16 :
130+ type_byte = payload [0 ]
131+ if type_byte not in (DIP18_TYPE_P2PKH , DIP18_TYPE_P2SH ):
111132 return (None , None )
112- if data [0 ] == 0 and len (decoded ) != 20 and len (decoded ) != 32 :
113- return (None , None )
114- if (data [0 ] == 0 and encoding != Encoding .BECH32 ) or (data [0 ] != 0 and encoding != Encoding .BECH32M ):
115- return (None , None )
116- return (data [0 ], decoded )
117-
133+ return (type_byte , bytes (payload [1 :]))
118134
119- def encode_segwit_address (hrp , witver , witprog ):
120- """Encode a segwit address."""
121- encoding = Encoding .BECH32 if witver == 0 else Encoding .BECH32M
122- ret = bech32_encode (encoding , hrp , [witver ] + convertbits (witprog , 8 , 5 ))
123- if decode_segwit_address (hrp , ret ) == (None , None ):
124- return None
125- return ret
126135
127136class TestFrameworkScript (unittest .TestCase ):
128- def test_segwit_encode_decode (self ):
129- def test_python_bech32 (addr ):
130- hrp = addr [:4 ]
131- self .assertEqual (hrp , "bcrt" )
132- (witver , witprog ) = decode_segwit_address (hrp , addr )
133- self .assertEqual (encode_segwit_address (hrp , witver , witprog ), addr )
134-
135- # P2WPKH
136- test_python_bech32 ('bcrt1qthmht0k2qnh3wy7336z05lu2km7emzfpm3wg46' )
137- # P2WSH
138- test_python_bech32 ('bcrt1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq3xueyj' )
139- test_python_bech32 ('bcrt1qft5p2uhsdcdc3l2ua4ap5qqfg4pjaqlp250x7us7a8qqhrxrxfsqseac85' )
140- # P2TR
141- test_python_bech32 ('bcrt1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqc8gma6' )
137+ def test_platform_encode_decode (self ):
138+ def test_platform_roundtrip (hrp , addr , expected_type ):
139+ typ , payload = decode_platform_address (hrp , addr )
140+ self .assertIsNotNone (typ )
141+ self .assertEqual (typ , expected_type )
142+ if expected_type == DIP18_TYPE_P2PKH :
143+ self .assertEqual (encode_platform_p2pkh (hrp , payload ), addr )
144+ else :
145+ self .assertEqual (encode_platform_p2sh (hrp , payload ), addr )
146+
147+ # DIP-18 P2PKH
148+ test_platform_roundtrip ('dash' , 'dash1krma5z3ttj75la4m93xcndna9ullamq9y5e9n5rs' , DIP18_TYPE_P2PKH )
149+ test_platform_roundtrip ('tdash' , 'tdash1krma5z3ttj75la4m93xcndna9ullamq9y5fzq2j7' , DIP18_TYPE_P2PKH )
150+ # DIP-18 P2SH
151+ test_platform_roundtrip ('dash' , 'dash1sppl5xpu70aka8nacc4kj2htflydspzkxch4cad6' , DIP18_TYPE_P2SH )
152+ test_platform_roundtrip ('tdash' , 'tdash1sppl5xpu70aka8nacc4kj2htflydspzkxc8jtru5' , DIP18_TYPE_P2SH )
0 commit comments