add ur xpub export

This commit is contained in:
Nick Klockenga
2022-01-06 22:10:16 -05:00
parent 6cfae5c2ce
commit afc3d9c9d2
2 changed files with 86 additions and 7 deletions
+4 -1
View File
@@ -10,6 +10,8 @@ from seedsigner.helpers.ur2.ur_decoder import URDecoder
from seedsigner.helpers.bcur import (cbor_decode, bc32decode)
from seedsigner.models import QRType, Seed
from urtypes.crypto import PSBT as UR_PSBT
###
### DecodeQR Class
### Purpose: used to process images or string data from animated qr codes with psbt data to create binary/base64 psbt
@@ -141,7 +143,8 @@ class DecodeQR:
if self.complete:
if self.qr_type == QRType.PSBTUR2:
cbor = self.ur_decoder.result_message().cbor
return cbor_decode(cbor)
return UR_PSBT.from_cbor(cbor).data
# return cbor_decode(cbor)
elif self.qr_type == QRType.PSBTSPECTER:
return self.specter_qr.getData()
elif self.qr_type == QRType.PSBTURLEGACY:
+82 -6
View File
@@ -9,6 +9,9 @@ from seedsigner.helpers.bcur import (bc32encode, cbor_encode, bcur_encode)
from seedsigner.helpers.qr import QR
from seedsigner.models import Seed, QRType, EncodeQRDensity
from urtypes.crypto import PSBT as UR_PSBT
from urtypes.crypto import Account, HDKey, Output, Keypath, PathComponent, SCRIPT_EXPRESSION_TAG_MAP
###
### EncodeQR Class
### Purpose: used to encode psbt for displaying as qr image
@@ -64,7 +67,7 @@ class EncodeQR:
elif self.qr_type == QRType.SEEDSSQR:
self.encoder = SeedSSQR(self.seed_phrase, self.wordlist)
elif self.qr_type == QRType.XPUBQR:
self.encoder = XPubQR(self.seed_phrase, self.passphrase, self.derivation, self.network, self.wordlist)
self.encoder = URXPubQR(self.seed_phrase, self.passphrase, self.derivation, self.network, self.qr_density, self.wordlist)
elif self.qr_type == QRType.SPECTERXPUBQR:
self.encoder = SpecterXPubQR(self.seed_phrase, self.passphrase, self.derivation, self.network, self.qr_density, self.wordlist)
else:
@@ -100,10 +103,8 @@ class UREncodePSBTQR:
def __init__(self, p, qr_density):
self.psbt = p
self.qr_max_fragement_size = 20
cbor_encoder = CBOREncoder()
cbor_encoder.encodeBytes(self.psbt.serialize())
qr_ur_bytes = UR("crypto-psbt", cbor_encoder.get_bytes())
qr_ur_bytes = UR("crypto-psbt", UR_PSBT(self.psbt.serialize()).to_cbor())
if qr_density == EncodeQRDensity.LOW:
self.qr_max_fragement_size = 10
@@ -313,4 +314,79 @@ class SpecterXPubQR(XPubQR):
return len(self.parts)
def isComplete(self):
return self.sent_complete
return self.sent_complete
class URXPubQR(XPubQR):
def __init__(self, seed_phrase, passphrase, derivation, network, qr_density, wordlist):
XPubQR.__init__(self, seed_phrase, passphrase, derivation, network, wordlist)
if qr_density == EncodeQRDensity.LOW:
self.qr_max_fragement_size = 10
elif qr_density == EncodeQRDensity.MEDIUM:
self.qr_max_fragement_size = 30
elif qr_density == EncodeQRDensity.HIGH:
self.qr_max_fragement_size = 120
def derivation_to_keypath(path: str) -> list:
arr = path.split("/")
if arr[0] == "m":
arr = arr[1:]
if len(arr) == 0:
return Keypath([],self.root.my_fingerprint, None)
if arr[-1] == "":
# trailing slash
arr = arr[:-1]
for i, e in enumerate(arr):
if e[-1] == "h" or e[-1] == "'":
arr[i] = PathComponent(int(e[:-1]), True)
else:
arr[i] = PathComponent(int(e), False)
return Keypath(arr, self.root.my_fingerprint, None)
origin = derivation_to_keypath(derivation)
self.ur_hdkey = HDKey({ 'key': self.xpub.key.serialize(),
'chain_code': self.xpub.chain_code,
'origin': origin,
'parent_fingerprint': self.xpub.fingerprint})
ur_outputs = []
if len(origin.components) > 0:
if origin.components[0].index == 84: # Native Single Sig
ur_outputs.append(Output([SCRIPT_EXPRESSION_TAG_MAP[404]],self.ur_hdkey))
elif origin.components[0].index == 49: # Nested Single Sig
ur_outputs.append(Output([SCRIPT_EXPRESSION_TAG_MAP[400], SCRIPT_EXPRESSION_TAG_MAP[404]],self.ur_hdkey))
elif origin.components[0].index == 48: # Multisig
if len(origin.components) >= 4:
if origin.components[3].index == 2: # Native Multisig
ur_outputs.append(Output([SCRIPT_EXPRESSION_TAG_MAP[401]],self.ur_hdkey))
elif origin.components[3].index == 1: # Nested Multisig
ur_outputs.append(Output([SCRIPT_EXPRESSION_TAG_MAP[400], SCRIPT_EXPRESSION_TAG_MAP[401]],self.ur_hdkey))
# If empty, add all script types
if len(ur_outputs) == 0:
ur_outputs.append(Output([SCRIPT_EXPRESSION_TAG_MAP[404]],self.ur_hdkey))
ur_outputs.append(Output([SCRIPT_EXPRESSION_TAG_MAP[400], SCRIPT_EXPRESSION_TAG_MAP[404]],self.ur_hdkey))
ur_outputs.append(Output([SCRIPT_EXPRESSION_TAG_MAP[401]],self.ur_hdkey))
ur_outputs.append(Output([SCRIPT_EXPRESSION_TAG_MAP[400], SCRIPT_EXPRESSION_TAG_MAP[401]],self.ur_hdkey))
ur_outputs.append(Output([SCRIPT_EXPRESSION_TAG_MAP[403]],self.ur_hdkey))
ur_account = Account(self.root.my_fingerprint, ur_outputs)
qr_ur_bytes = UR("crypto-account", ur_account.to_cbor())
self.ur2_encode = UREncoder(qr_ur_bytes, self.qr_max_fragement_size, 0)
def seqLen(self):
return self.ur2_encode.fountain_encoder.seq_len()
def nextPart(self) -> str:
return self.ur2_encode.next_part().upper()
def isComplete(self):
return self.ur2_encode.is_complete()