示例#1
0
文件: auth.py 项目: syscoin/firmware
    async def interact(self):
        # Prompt user w/ details and get approval
        from main import dis

        # step 1: parse PSBT from sflash into in-memory objects.
        dis.fullscreen("Validating...")

        try:
            with SFFile(TXN_INPUT_OFFSET, length=self.psbt_len) as fd:
                self.psbt = psbtObject.read_psbt(fd)
        except BaseException as exc:
            if isinstance(exc, MemoryError):
                msg = "Transaction is too complex"
                exc = None
            else:
                msg = "PSBT parse failed"

            return await self.failure(msg, exc)

        # Do some analysis/ validation
        try:
            await self.psbt.validate()      # might do UX: accept multisig import
            self.psbt.consider_inputs()
            self.psbt.consider_keys()
            self.psbt.consider_outputs()
        except FraudulentChangeOutput as exc:
            print('FraudulentChangeOutput: ' + exc.args[0])
            return await self.failure(exc.args[0], title='Change Fraud')
        except FatalPSBTIssue as exc:
            print('FatalPSBTIssue: ' + exc.args[0])
            return await self.failure(exc.args[0])
        except BaseException as exc:
            del self.psbt
            gc.collect()

            if isinstance(exc, MemoryError):
                msg = "Transaction is too complex"
                exc = None
            else:
                msg = "Invalid PSBT"

            return await self.failure(msg, exc)

        # step 2: figure out what we are approving, so we can get sign-off
        # - outputs, amounts
        # - fee 
        #
        # notes: 
        # - try to handle lots of outputs
        # - cannot calc fee as sat/byte, only as percent
        # - somethings are 'warnings':
        #       - fee too big
        #       - inputs we can't sign (no key)
        #
        try:
            msg = uio.StringIO()

            # mention warning at top
            wl= len(self.psbt.warnings)
            if wl == 1:
                msg.write('(1 warning below)\n\n')
            elif wl >= 2:
                msg.write('(%d warnings below)\n\n' % wl)

            self.output_summary_text(msg)
            gc.collect()

            fee = self.psbt.calculate_fee()
            if fee is not None:
                msg.write("\nNetwork fee:\n%s %s\n" % self.chain.render_value(fee))

            if self.psbt.warnings:
                msg.write('\n---WARNING---\n\n')

                for label,m in self.psbt.warnings:
                    msg.write('- %s: %s\n\n' % (label, m))

            msg.write("\nPress OK to approve and sign transaction. X to abort.")

            ch = await ux_show_story(msg, title="OK TO SEND?")
        except MemoryError:
            # recovery? maybe.
            try:
                del self.psbt
                del msg
            except: pass        # might be NameError since we don't know how far we got
            gc.collect()

            msg = "Transaction is too complex"
            return await self.failure(msg)

        if ch != 'y':
            # they don't want to!
            self.refused = True
            await ux_dramatic_pause("Refused.", 1)

            del self.psbt

            self.done()
            return

        # do the actual signing.
        try:
            gc.collect()
            self.psbt.sign_it()
        except FraudulentChangeOutput as exc:
            return await self.failure(exc.args[0], title='Change Fraud')
        except MemoryError:
            msg = "Transaction is too complex"
            return await self.failure(msg)
        except BaseException as exc:
            return await self.failure("Signing failed late", exc)

        if self.approved_cb:
            # for micro sd case
            await self.approved_cb(self.psbt)
            self.done()
            return

        try:
            # re-serialize the PSBT back out
            with SFFile(TXN_OUTPUT_OFFSET, max_size=MAX_TXN_LEN, message="Saving...") as fd:
                await fd.erase()

                if self.do_finalize:
                    self.psbt.finalize(fd)
                else:
                    self.psbt.serialize(fd)

                self.result = (fd.tell(), fd.checksum.digest())

            self.done()

        except BaseException as exc:
            return await self.failure("PSBT output failed", exc)
示例#2
0
        here = orig.read(256)
        if not here: break

        if here[0:10] == b'70736274ff':
            is_hex = True

        if is_hex:
            here = a2b_hex(here)

        wr_fd.write(here)
        tl += len(here)

from psbt import psbtObject, FatalPSBTIssue

rd_fd = SFFile(0, tl)
obj = psbtObject.read_psbt(rd_fd)

# all these trival test cases now fail validation for various reasons...
try:
    obj.validate()
    print("should fail")
except AssertionError:
    pass
except FatalPSBTIssue:
    pass

obj.serialize(out_fd)
out_tl = out_fd.tell()

# copy back into MacOS filesystem
with open('readback.psbt', 'wb') as rb:
示例#3
0
from uio import BytesIO
from sffile import SFFile

# NOTE: not a psbt, just a txn
# - 2 ins, 2 outs
unsigned = a2b_hex('0100000002fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f0000000000eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac11000000')


fd = SFFile(0, max_size=65536)
list(fd.erase())
fd.write(b'psbt\xff\x01\x00' + bytes([len(unsigned)]) + unsigned + (b'\0'*8))
psbt_len = fd.tell()

rfd = SFFile(0, psbt_len)

p = psbtObject.read_psbt(rfd)

#p.validate()       # failed because no subpaths; don't care

amt = 600000000
sc = a2b_hex('1976a9141d0f172a0ecb48aee1be1f2687d2963ae33f71a188ac')

outpt2 = a2b_hex('ef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff')

replacement = CTxIn()
replacement.deserialize(BytesIO(outpt2))

digest = p.make_txn_segwit_sighash(0, replacement, amt, sc, 0x01)

print('Got: ' + b2a_hex(digest).decode('ascii'))
assert digest == a2b_hex('c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670')
示例#4
0
文件: auth.py 项目: Coldcard/firmware
    async def interact(self):
        # Prompt user w/ details and get approval
        from glob import dis, hsm_active

        # step 1: parse PSBT from sflash into in-memory objects.

        try:
            dis.fullscreen("Reading...")
            with SFFile(TXN_INPUT_OFFSET, length=self.psbt_len) as fd:
                self.psbt = psbtObject.read_psbt(fd)
        except BaseException as exc:
            if isinstance(exc, MemoryError):
                msg = "Transaction is too complex"
                exc = None
            else:
                msg = "PSBT parse failed"

            return await self.failure(msg, exc)

        dis.fullscreen("Validating...")

        # Do some analysis/ validation
        try:
            await self.psbt.validate()      # might do UX: accept multisig import
            self.psbt.consider_inputs()
            self.psbt.consider_keys()
            self.psbt.consider_outputs()
        except FraudulentChangeOutput as exc:
            print('FraudulentChangeOutput: ' + exc.args[0])
            return await self.failure(exc.args[0], title='Change Fraud')
        except FatalPSBTIssue as exc:
            print('FatalPSBTIssue: ' + exc.args[0])
            return await self.failure(exc.args[0])
        except BaseException as exc:
            del self.psbt
            gc.collect()

            if isinstance(exc, MemoryError):
                msg = "Transaction is too complex"
                exc = None
            else:
                msg = "Invalid PSBT"

            return await self.failure(msg, exc)

        # step 2: figure out what we are approving, so we can get sign-off
        # - outputs, amounts
        # - fee 
        #
        # notes: 
        # - try to handle lots of outputs
        # - cannot calc fee as sat/byte, only as percent
        # - somethings are 'warnings':
        #       - fee too big
        #       - inputs we can't sign (no key)
        #
        try:
            msg = uio.StringIO()

            # mention warning at top
            wl= len(self.psbt.warnings)
            if wl == 1:
                msg.write('(1 warning below)\n\n')
            elif wl >= 2:
                msg.write('(%d warnings below)\n\n' % wl)

            self.output_summary_text(msg)
            gc.collect()

            fee = self.psbt.calculate_fee()
            if fee is not None:
                msg.write("\nNetwork fee:\n%s %s\n" % self.chain.render_value(fee))

            # NEW: show where all the change outputs are going
            self.output_change_text(msg)
            gc.collect()

            if self.psbt.warnings:
                msg.write('\n---WARNING---\n\n')

                for label, m in self.psbt.warnings:
                    msg.write('- %s: %s\n\n' % (label, m))

            if self.do_visualize:
                # stop here and just return the text of approval message itself
                self.result = await self.save_visualization(msg, (self.stxn_flags & STXN_SIGNED))
                del self.psbt
                self.done()

                return

            if not hsm_active:
                msg.write("\nPress OK to approve and sign transaction. X to abort.")
                ch = await ux_show_story(msg, title="OK TO SEND?")
            else:
                ch = await hsm_active.approve_transaction(self.psbt, self.psbt_sha, msg.getvalue())
                dis.progress_bar(1)     # finish the Validating...

        except MemoryError:
            # recovery? maybe.
            try:
                del self.psbt
                del msg
            except: pass        # might be NameError since we don't know how far we got
            gc.collect()

            msg = "Transaction is too complex"
            return await self.failure(msg)

        if ch != 'y':
            # they don't want to!
            self.refused = True

            await ux_dramatic_pause("Refused.", 1)

            del self.psbt

            self.done()
            return

        # do the actual signing.
        try:
            dis.fullscreen('Wait...')
            gc.collect()           # visible delay causes by this but also sign_it() below
            self.psbt.sign_it()
        except FraudulentChangeOutput as exc:
            return await self.failure(exc.args[0], title='Change Fraud')
        except MemoryError:
            msg = "Transaction is too complex"
            return await self.failure(msg)
        except BaseException as exc:
            return await self.failure("Signing failed late", exc)

        if self.approved_cb:
            # for micro sd case
            await self.approved_cb(self.psbt)
            self.done()
            return

        txid = None
        try:
            # re-serialize the PSBT back out
            with SFFile(TXN_OUTPUT_OFFSET, max_size=MAX_TXN_LEN, message="Saving...") as fd:
                await fd.erase()

                if self.do_finalize:
                    txid = self.psbt.finalize(fd)
                else:
                    self.psbt.serialize(fd)

                self.result = (fd.tell(), fd.checksum.digest())

            self.done(redraw=(not txid))

        except BaseException as exc:
            return await self.failure("PSBT output failed", exc)

        if self.do_finalize and txid and not hsm_active:
            # Show txid when we can; advisory
            # - maybe even as QR, hex-encoded in alnum mode
            tmsg = txid

            if version.has_fatram:
                tmsg += '\n\nPress 1 for QR Code of TXID.'

            ch = await ux_show_story(tmsg, "Final TXID", escape='1')

            if version.has_fatram and ch=='1':
                await show_qr_code(txid, True)
示例#5
0
    async def interact(self):
        # Prompt user w/ details and get approval
        from common import dis

        # step 1: parse PSBT from sflash into in-memory objects.
        dis.fullscreen("Validating...")

        if self.psbt == None:
            try:
                # Read TXN from SPI Flash (we put it there whether it came from a QR code or an SD card)
                with SFFile(TXN_INPUT_OFFSET, length=self.psbt_len) as fd:
                    self.psbt = psbtObject.read_psbt(fd)
            except BaseException as exc:
                if isinstance(exc, MemoryError):
                    msg = "Transaction is too complex"
                    exc = None
                else:
                    msg = "PSBT parse failed"

                return await self.failure(msg, exc)

        # Do some analysis/validation
        try:
            await self.psbt.validate()      # might do UX: accept multisig import
            self.psbt.consider_inputs()
            self.psbt.consider_keys()
            self.psbt.consider_outputs()
        except FraudulentChangeOutput as exc:
            print('FraudulentChangeOutput: ' + exc.args[0])
            return await self.failure(exc.args[0], title='Change Fraud')
        except FatalPSBTIssue as exc:
            print('FatalPSBTIssue: ' + exc.args[0])
            return await self.failure(exc.args[0])
        except BaseException as exc:
            del self.psbt
            gc.collect()

            if isinstance(exc, MemoryError):
                msg = "Transaction is too complex"
                exc = None
            else:
                msg = "Invalid PSBT"

            return await self.failure(msg, exc)

        # step 2: figure out what we are approving, so we can get sign-off
        # - outputs, amounts
        # - fee
        #
        # notes:
        # - try to handle lots of outputs
        # - cannot calc fee as sat/byte, only as percent
        # - somethings are 'warnings':
        #       - fee too big
        #       - inputs we can't sign (no key)
        #
        try:
            outputs = uio.StringIO()
            outputs.write('Amount:')

            first = True
            for idx, tx_out in self.psbt.output_iter():
                outp = self.psbt.outputs[idx]
                if outp.is_change:
                    continue

                if first:
                    first = False
                else:
                    outputs.write('\n')

                outputs.write(self.render_output(tx_out))

            # print('total_out={} total_in={} change={}'.format=(self.psbt.total_value_out, self.psbt.total_value_in, self.psbt.total_value_in - self.psbt.total_value_out))
            pages = [
                {'title': 'Sign Txn', 'msg': outputs.getvalue(), 'center': True, 'center_vertically': True},
                {'title': 'Sign Txn', 'msg': self.render_change_text(), 'center': True, 'center_vertically': True},
            ]

            warnings = self.render_warnings()
            print('warnings = "{}"'.format(warnings))
            if warnings != None:
                pages.append(
                        {'title': 'Sign Txn', 'msg': warnings, 'center': True, 'center_vertically': True, 'right_btn': 'SIGN!'}
                )

            if self.do_visualize:
                # stop here and just return the text of approval message itself
                self.result = await self.save_visualization(msg, (self.stxn_flags & STXN_SIGNED))
                del self.psbt
                self.done()

                return

            result = await ux_show_story_sequence(pages)

        except MemoryError:
            # recovery? maybe.
            try:
                del self.psbt
                del msg
            except:
                pass        # might be NameError since we don't know how far we got
            gc.collect()

            msg = "Transaction is too complex"
            return await self.failure(msg)

        if result != 'y':
            # User chose not to sign the transaction
            self.refused = True

            # TODO: ux_confirm() instead?
            # await ux_dramatic_pause("Refused.", 1)

            del self.psbt

            self.done()
            return

        # do the actual signing.
        try:
            gc.collect()
            self.psbt.sign_it()
        except FraudulentChangeOutput as exc:
            return await self.failure(exc.args[0], title='Change Fraud')
        except MemoryError:
            msg = "Transaction is too complex"
            return await self.failure(msg)
        except BaseException as exc:
            return await self.failure("Signing failed late", exc)

        if self.approved_cb:
            # for micro sd case
            await self.approved_cb(self.psbt)
            self.done()
            return

        try:
            # re-serialize the PSBT back out
            with SFFile(TXN_OUTPUT_OFFSET, max_size=MAX_TXN_LEN, message="Saving...") as fd:
                await fd.erase()

                if self.do_finalize:
                    self.psbt.finalize(fd)
                else:
                    self.psbt.serialize(fd)

                self.result = (fd.tell(), fd.checksum.digest())

            self.done()

        except BaseException as exc:
            return await self.failure("PSBT output failed", exc)