more work

This commit is contained in:
newtonick
2021-07-31 22:52:18 -04:00
parent 5629eac07c
commit 9eb609165b
5 changed files with 167 additions and 95 deletions
+21 -14
View File
@@ -80,23 +80,30 @@ class DecodeQR:
def getPSBT(self):
if self.complete:
try:
if self.qr_type == QRType.PSBTUR2:
cbor = self.ur_decoder.result_message().cbor
return psbt.PSBT.parse(cbor_decode(cbor))
elif self.qr_type == QRType.PSBTSPECTER:
return psbt.PSBT.parse(self.specter_qr.getData())
elif self.qr_type == QRType.PSBTURLEGACY:
return psbt.PSBT.parse(self.legacy_ur.getData())
elif self.qr_type == QRType.PSBTBASE64:
return psbt.PSBT.parse(self.base64_qr.getData())
except:
return None
data = self.getDataPSBT()
if data != None:
try:
return psbt.PSBT.parse(data)
except:
return None
return None
def getDataPSBT(self):
if self.complete:
if self.qr_type == QRType.PSBTUR2:
cbor = self.ur_decoder.result_message().cbor
return cbor_decode(cbor)
elif self.qr_type == QRType.PSBTSPECTER:
return self.specter_qr.getData()
elif self.qr_type == QRType.PSBTURLEGACY:
return self.legacy_ur.getData()
elif self.qr_type == QRType.PSBTBASE64:
return self.base64_qr.getData()
return None
def getBase64PSBT(self):
if self.complete:
data = self.getData()
data = self.getDataPSBT()
b64_psbt = b2a_base64(data)
if b64_psbt[-1:] == b"\n":
@@ -163,7 +170,7 @@ class DecodeQR:
return QRType.PSBTURLEGACY
elif re.search(r'\d{48,96}', s):
return QRType.SEEDSSQR
elif DecodePSBTQR.isBase64PSBT(s):
elif DecodeQR.isBase64PSBT(s):
return QRType.PSBTBASE64
else:
return QRType.INVALID
+3 -3
View File
@@ -57,7 +57,7 @@ class UREncodePSBTQR:
def __init__(self, p, qr_density):
self.psbt = p
self.qr_max_fragement_size = 50
self.qr_max_fragement_size = 10
cbor_encoder = CBOREncoder()
cbor_encoder.encodeBytes(self.psbt.serialize())
@@ -66,9 +66,9 @@ class UREncodePSBTQR:
self.ur2_encode = UREncoder(qr_ur_bytes,self.qr_max_fragement_size,0)
if qr_density == EncodePSBTQRDensity.LOW:
self.qr_max_fragement_size = 20
self.qr_max_fragement_size = 10
elif qr_density == EncodePSBTQRDensity.MEDIUM:
self.qr_max_fragement_size = 50
self.qr_max_fragement_size = 20
elif qr_density == EncodePSBTQRDensity.HIGH:
self.qr_max_fragement_size = 80
+45 -26
View File
@@ -14,28 +14,48 @@ class PSBTParser():
self.spend_amount = 0
self.change_amount = 0
self.fee_amount = 0
self.input_amount = 0
self.destination_addresses = []
self.self_addresses = []
self.seed = None
self.root = None
if self.seed_phrase != None:
self.parse(self.psbt,self.seed_phrase,self.passphrase,self.network)
def __setSeedRoot(self, seed_phrase, passphrase, network):
self.seed = bip39.mnemonic_to_seed(" ".join(seed_phrase).strip(), passphrase)
self.root = bip32.HDKey.from_seed(self.seed, version=NETWORKS[network]["xprv"])
def parse(self, p, seed_phrase=[], passphrase="", network="main"):
if p == None:
is_psbt_empty = False
try:
if p == None:
is_psbt_empty = True
except:
pass
if is_psbt_empty:
return False
if seed_phrase == None or len(seed_phrase) not in (12,24):
if len(seed_phrase) == 0:
return False
self.__setSeedRoot(seed_phrase,passphrase,network)
rt = self.__parseInputs()
if rt == False:
return False
rt = self.__parseOutputs(self.seed_phrase, self.passphrase, self.network)
rt = self.__parseOutputs()
if rt == False:
return False
return True
def __parseInputs(self):
self.psbt.input_amount = 0
self.input_amount = 0
for inp in self.psbt.inputs:
self.input_amount += inp.witness_utxo.value
inp_policy = PSBTParser.__get_policy(inp, inp.witness_utxo.script_pubkey, self.psbt.xpubs)
@@ -45,11 +65,7 @@ class PSBTParser():
if self.policy != inp_policy:
raise RuntimeError("Mixed inputs in the transaction")
def __parseOutputs(self, seed_phrase, passphrase, network):
seed = bip39.mnemonic_to_seed((" ".join(seed_phrase)).strip(), passphrase)
root = bip32.HDKey.from_seed(seed, version=NETWORKS[network]["xprv"])
fingerprint = root.child(0).fingerprint
def __parseOutputs(self):
self.spend_amount = 0
self.change_amount = 0
self.fee_amount = 0
@@ -75,27 +91,30 @@ class PSBTParser():
sc = script.p2wsh(out.witness_script)
elif self.policy["type"] == "p2sh-p2wsh":
sc = script.p2sh(script.p2wsh(out.witness_script))
# single-sig
elif "pkh" in self.policy["type"] and fingerprint != None:
for pub in out.bip32_derivations:
# check if it is our key
if out.bip32_derivations[pub].fingerprint == fingerprint:
hdkey = root.derive(out.bip32_derivations[pub].derivation)
mypub = hdkey.key.get_public_key()
if mypub != pub:
raise ValueError("Derivation path doesn't look right")
# now check if provided scriptpubkey matches
sc = script.p2wpkh(mypub)
if sc == self.psbt.tx.vout[i].script_pubkey:
is_change = True
elif "pkh" in self.policy["type"]:
my_pubkey = None
# should be one or zero for single-key addresses
if len(out.bip32_derivations.values()) > 0:
der = list(out.bip32_derivations.values())[0].derivation
my_pubkey = self.root.derive(der)
if self.policy["type"] == "p2wpkh" and my_pubkey != None:
sc = script.p2wpkh(my_pubkey)
elif self.policy["type"] == "p2sh-p2wpkh" and my_pubkey != None:
sc = script.p2sh(script.p2wpkh(my_pubkey))
if sc.data == self.psbt.tx.vout[i].script_pubkey.data:
is_change = True
if sc.data == self.psbt.tx.vout[i].script_pubkey.data:
is_change = True
if is_change:
self.change_amount += self.psbt.tx.vout[i].value
self.self_addresses.append(self.psbt.tx.vout[i].script_pubkey.address(NETWORKS[network]))
self.self_addresses.append(self.psbt.tx.vout[i].script_pubkey.address(NETWORKS[self.network]))
else:
self.spend_amount += self.tx.vout[i].value
self.destination_addresses.append(self.tx.vout[i].script_pubkey.address(NETWORKS[network]))
self.spend_amount += self.psbt.tx.vout[i].value
self.destination_addresses.append(self.psbt.tx.vout[i].script_pubkey.address(NETWORKS[self.network]))
self.fee_amount = self.psbt.fee()
return True
@@ -132,10 +151,10 @@ class PSBTParser():
if "p2wsh" in script_type and scope.witness_script is not None:
m, n, pubkeys = PSBTParser.__parse_multisig(scope.witness_script)
# check pubkeys are derived from cosigners
if len(pubkeys) > 0:
try:
cosigners = PSBTParser.__get_cosigners(pubkeys, scope.bip32_derivations, xpubs)
policy.update({"m": m, "n": n, "cosigners": cosigners})
else:
except:
policy.update({"m": m, "n": n})
return policy
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long