Custom Python P2WSH Auditor
Custom Python P2WSH Auditor
In this final guide, we will build a Python script that parses a Native SegWit Multisig (P2WSH) ScriptPubKey. The script will extract the 32-byte SHA256 hash and convert it into a human-readable bc1q address. Note that P2WSH addresses are much longer than P2WPKH addresses.
The P2WSH Address Auditor
# Bech32 constants
CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
def bech32_polymod(values):
generator = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]
chk = 1
for value in values:
top = chk \u003e\u003e 25
chk = (chk \u0026 0x1ffffff) \u003c\u003c 5 ^ value
for i in range(5):
chk ^= generator[i] if ((top \u003e\u003e i) \u0026 1) else 0
return chk
def bech32_hrp_expand(hrp):
return [ord(x) \u003e\u003e 5 for x in hrp] + [0] + [ord(x) \u0026 31 for x in hrp]
def convertbits(data, frombits, tobits, pad=True):
acc = 0
bits = 0
ret = []
maxv = (1 \u003c\u003c tobits) - 1
for value in data:
acc = (acc \u003c\u003c frombits) | value
bits += frombits
while bits \u003e= tobits:
bits -= tobits
ret.append((acc \u003e\u003e bits) \u0026 maxv)
if pad:
if bits:
ret.append((acc \u003c\u003c (tobits - bits)) \u0026 maxv)
return ret
def audit_p2wsh(script_hex):
# 1. Identify the Pattern (00 20 [32-byte hash])
if not (script_hex.startswith("0020") and len(script_hex) == 68):
print("[ERROR] Not a standard P2WSH ScriptPubKey!")
return
sh_hex = script_hex[4:]
sh_bytes = list(bytes.fromhex(sh_hex))
print(f"--- P2WSH Native Auditor ---")
print(f"[*] ScriptPubKey: {script_hex}")
print(f"[*] Script Hash: {sh_hex}")
# 2. Convert bytes to 5-bit groups for Bech32
# The '0' at the start is the Witness Version
data = [0] + convertbits(sh_bytes, 8, 5)
# 3. Calculate Checksum (BIP 173)
hrp = "bc"
combined = bech32_hrp_expand(hrp) + data
mod = bech32_polymod(combined + [0, 0, 0, 0, 0, 0]) ^ 1
checksum = [(mod \u003e\u003e 5 * (5 - i)) \u0026 31 for i in range(6)]
# 4. Final Encoding
address = hrp + "1" + "".join([CHARSET[d] for d in data + checksum])
print(f"[*] Derived Address: {address}")
print(f"[*] Length Check: {len(address)} characters (Expected: 62)")
# --- Simulation ---
# Case: A standard Native Multisig output
# (A real hash would be SHA256 of the multisig script)
p2wsh_script = "0020aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
audit_p2wsh(p2wsh_script)
How to Run the Auditor
-
Ensure you have Python 3 installed.
-
Copy the code into a file named
p2wsh_auditor.py. -
Run it using
python3 p2wsh_auditor.py.
Technical Takeaways
-
Bit Packing Complexity: Notice that because the hash is 32 bytes (256 bits), it doesn't divide evenly into 5-bit chunks (it requires 52 chunks + 4 bits padding). This is why the address is exactly 62 characters.
-
Visual Distinction: The long
bc1qaddresses are the hallmark of multisig security. If you see an address that is roughly 1.5x longer than a standard SegWit address, you are likely looking at a multisig vault. -
Optimal Scaling: By using Native P2WSH, the sender only pays for 34 bytes of script, no matter how many keys are actually protecting the funds.
Congratulations! You have completed the P2WSH (Native SegWit Multisig) module. You now understand the highest form of collaborative custody in Bitcoin.
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: