Custom Python P2SH Auditor
Custom Python P2SH Auditor
In this final guide, we will build a Python script that takes a raw P2SH ScriptPubKey and extracts the 20-byte script hash. We will then implement the Base58Check encoding with the P2SH version byte (0x05) to derive the corresponding "3" address.
The P2SH Address Auditor
import hashlib
# Standard Base58 alphabet
BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
def base58_encode(raw_bytes):
n = int.from_bytes(raw_bytes, 'big')
res = ""
while n \u003e 0:
n, r = divmod(n, 58)
res = BASE58_ALPHABET[r] + res
# Handle leading zeros
pad = 0
for b in raw_bytes:
if b == 0: pad += 1
else: break
# Version byte 0x05 encodes to '3' in Base58
return res
def decode_p2sh(script_hex):
# 1. Check for standard P2SH pattern
# a9 (HASH160) 14 (PUSH 20) ... 87 (EQUAL)
if not (script_hex.startswith("a914") and script_hex.endswith("87")):
print("[ERROR] Not a standard P2SH script!")
return
# 2. Extract the 20-byte script hash
sh_hex = script_hex[4:-2]
sh_bytes = bytes.fromhex(sh_hex)
print(f"--- P2SH Script Audit ---")
print(f"[*] Raw Script: {script_hex}")
print(f"[*] Script Hash: {sh_hex}")
# 3. Base58Check Encoding (Version 0x05)
# Step A: Prepend Version Byte (0x05 for P2SH Mainnet)
versioned_sh = b'\\x05' + sh_bytes
# Step B: Double SHA256 for checksum
first_sha = hashlib.sha256(versioned_sh).digest()
checksum = hashlib.sha256(first_sha).digest()[:4]
# Step C: Append Checksum and Encode
final_payload = versioned_sh + checksum
address = base58_encode(final_payload)
print(f"[*] Derived Address: {address}")
if address.startswith("3"):
print("[STATUS] Validation Successful: This is a standard P2SH Address.")
# --- Simulation ---
# Case: A real-world P2SH ScriptPubKey
# address: 3Em92CofpTfXqU2iY73G6hA5o6gG7hA5o6
p2sh_script = "a9148f14848d56b0d918901e18d601d51c3a647d6c6e87"
decode_p2sh(p2sh_script)
How to Run the Auditor
-
Ensure you have Python 3 installed.
-
Copy the code into a file named
p2sh_auditor.py. -
Run it using
python3 p2sh_auditor.py.
Technical Takeaways
-
Version Byte Magic: Notice how using
0x05instead of0x00completely changes the first character of the address to a3. This is how wallets distinguish between P2PKH and P2SH. -
Blind Verification: We were able to derive the address without knowing if the underlying script is a multisig, a timelock, or something else. This is the core privacy feature of P2SH.
-
Soft Fork Integrity: Because P2SH is just
OP_HASH160andOP_EQUAL, it was backward compatible with nodes that didn't know how to "unwrap" and execute the Redeem Script.
Congratulations! You have completed the P2SH (Pay-to-Script-Hash) module. You now understand the gateway to complex Bitcoin smart contracts.
TeachMeBitcoin is an ad-free, open-source educational repository curated by a passionate team of Bitcoin researchers and educators for public benefit. If you found our articles helpful, please consider supporting our hosting and ongoing content updates with a clean donation: