upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/scripts/verify-utxo-proof.py
diff options
context:
space:
mode:
authorNsable-sh <nsable-sh@noreply.git.bitflash.network>2026-08-11 14:13:26 -0300
committerNsable-sh <nsable-sh@noreply.git.bitflash.network>2026-08-11 14:13:26 -0300
commit1839347459759fb3b23cc747ec4368b724fee008 (patch)
treee5f6f7e13b6dd9eb260d7c75bafa19d873435c5c /scripts/verify-utxo-proof.py
parenta83fae37099cb102beb5a4c174a4abe6ef3f24a4 (diff)
tools: harden chain audit scripts
Diffstat (limited to 'scripts/verify-utxo-proof.py')
-rw-r--r--scripts/verify-utxo-proof.py23
1 files changed, 4 insertions, 19 deletions
diff --git a/scripts/verify-utxo-proof.py b/scripts/verify-utxo-proof.py
index 31099f7..c29caa9 100644
--- a/scripts/verify-utxo-proof.py
+++ b/scripts/verify-utxo-proof.py
@@ -7,6 +7,7 @@ import json
7import sys 7import sys
8from pathlib import Path 8from pathlib import Path
9 9
10import bitflash_chain as chain
10 11
11SCHEMA = "bitflash-utxo-inclusion-proof-1" 12SCHEMA = "bitflash-utxo-inclusion-proof-1"
12LEAF_DOMAIN = "BTFUTXO1" 13LEAF_DOMAIN = "BTFUTXO1"
@@ -17,22 +18,6 @@ def canonical_bytes(obj):
17 return (json.dumps(obj, sort_keys=True, separators=(",", ":"), ensure_ascii=True) + "\n").encode("ascii") 18 return (json.dumps(obj, sort_keys=True, separators=(",", ":"), ensure_ascii=True) + "\n").encode("ascii")
18 19
19 20
20def sha256(data):
21 return hashlib.sha256(data).digest()
22
23
24def utxo_leaf_hash(outpoint, utxo):
25 payload = "|".join([
26 LEAF_DOMAIN,
27 outpoint,
28 str(utxo["value_satoshis"]),
29 utxo["script_pub_key_hex"],
30 str(utxo["created_height"]),
31 utxo["created_txid"],
32 ]).encode("ascii")
33 return sha256(payload)
34
35
36def load_proof(path): 21def load_proof(path):
37 try: 22 try:
38 return json.loads(Path(path).read_text(encoding="ascii")) 23 return json.loads(Path(path).read_text(encoding="ascii"))
@@ -59,7 +44,7 @@ def verify(proof, expected_root=None):
59 failures.append("target outpoint does not match txid:vout") 44 failures.append("target outpoint does not match txid:vout")
60 45
61 try: 46 try:
62 current = utxo_leaf_hash(outpoint, utxo) 47 current = chain.utxo_leaf_hash(outpoint, utxo)
63 leaf_ok = target.get("leaf_hash") == current.hex() 48 leaf_ok = target.get("leaf_hash") == current.hex()
64 except Exception as e: 49 except Exception as e:
65 failures.append("could not hash target leaf: %s" % e) 50 failures.append("could not hash target leaf: %s" % e)
@@ -79,9 +64,9 @@ def verify(proof, expected_root=None):
79 failures.append("bad sibling hash length at proof level %d" % i) 64 failures.append("bad sibling hash length at proof level %d" % i)
80 side = step.get("side") 65 side = step.get("side")
81 if side == "right": 66 if side == "right":
82 current = sha256(NODE_DOMAIN + current + sibling) 67 current = chain.sha256(NODE_DOMAIN + current + sibling)
83 elif side == "left": 68 elif side == "left":
84 current = sha256(NODE_DOMAIN + sibling + current) 69 current = chain.sha256(NODE_DOMAIN + sibling + current)
85 else: 70 else:
86 failures.append("bad sibling side at proof level %d" % i) 71 failures.append("bad sibling side at proof level %d" % i)
87 72