def _validate(state: State):
    from apps.monero.signing import RctType

    if state.current_output_index + 1 != state.output_count:
        raise ValueError("Invalid out num")

    # Test if \sum Alpha == \sum A
    if state.rct_type == RctType.Simple:
        utils.ensure(crypto.sc_eq(state.sumout, state.sumpouts_alphas))

    # Fee test
    if state.fee != (state.summary_inputs_money - state.summary_outs_money):
        raise ValueError(
            "Fee invalid %s vs %s, out: %s"
            % (
                state.fee,
                state.summary_inputs_money - state.summary_outs_money,
                state.summary_outs_money,
            )
        )

    if state.summary_outs_money > state.summary_inputs_money:
        raise ValueError(
            "Transaction inputs money (%s) less than outputs money (%s)"
            % (state.summary_inputs_money, state.summary_outs_money)
        )
Пример #2
0
    def prove_setup(self, sv, gamma, proof_v8=False):
        utils.ensure(len(sv) == len(gamma), "|sv| != |gamma|")
        utils.ensure(len(sv) > 0, "sv empty")

        self.proof_sec = crypto.random_bytes(64)
        self._det_mask_init()
        gc.collect()
        sv = [crypto.encodeint(x) for x in sv]
        gamma = [crypto.encodeint(x) for x in gamma]

        M, logM = 1, 0
        while M <= _BP_M and M < len(sv):
            logM += 1
            M = 1 << logM
        MN = M * _BP_N

        V = _ensure_dst_keyvect(None, len(sv))
        for i in range(len(sv)):
            add_keys2(tmp_bf_0, gamma[i], sv[i], _XMR_H)
            if not proof_v8:
                scalarmult_key(tmp_bf_0, tmp_bf_0, _INV_EIGHT)
            V.read(i, tmp_bf_0)

        aL, aR = self.aX_vcts(sv, MN)
        return M, logM, aL, aR, V, gamma
Пример #3
0
 def matches(self, multisig: MultisigRedeemScriptType):
     fp = multisig_fingerprint(multisig)
     ensure(fp is not None)
     if self.mismatch is False and self.fingerprint == fp:
         return True
     else:
         return False
Пример #4
0
def write_uint32_le(w: bytearray, n: int) -> int:
    ensure(0 <= n <= 0xFFFFFFFF)
    w.append(n & 0xFF)
    w.append((n >> 8) & 0xFF)
    w.append((n >> 16) & 0xFF)
    w.append((n >> 24) & 0xFF)
    return 4
Пример #5
0
    def set_serialized_signature(self, index: int, signature: bytes) -> None:
        # Only one signature per TxRequest can be serialized.
        assert self.tx_req.serialized is not None
        ensure(self.tx_req.serialized.signature is None)

        self.tx_req.serialized.signature_index = index
        self.tx_req.serialized.signature = signature
Пример #6
0
    def preimage_hash(
        self,
        coin: CoinInfo,
        tx: SignTx,
        txi: TxInputType,
        pubkeyhash: bytes,
        sighash: int,
    ) -> bytes:
        h_preimage = HashWriter(sha256())

        ensure(not tx.overwintered)

        write_uint32(h_preimage, tx.version)  # nVersion
        write_bytes(h_preimage, bytearray(self.get_prevouts_hash(coin)))  # hashPrevouts
        write_bytes(h_preimage, bytearray(self.get_sequence_hash(coin)))  # hashSequence

        write_bytes_reversed(h_preimage, txi.prev_hash)  # outpoint
        write_uint32(h_preimage, txi.prev_index)  # outpoint

        script_code = self.derive_script_code(txi, pubkeyhash)  # scriptCode
        write_varint(h_preimage, len(script_code))
        write_bytes(h_preimage, script_code)

        write_uint64(h_preimage, txi.amount)  # amount
        write_uint32(h_preimage, txi.sequence)  # nSequence
        write_bytes(h_preimage, bytearray(self.get_outputs_hash(coin)))  # hashOutputs
        write_uint32(h_preimage, tx.lock_time)  # nLockTime
        write_uint32(h_preimage, sighash)  # nHashType

        return get_tx_hash(h_preimage, double=coin.sign_hash_double)
Пример #7
0
 def __exit__(self, exc_type, exc_value, tb):
     if exc_type is None:
         ensure(False, f"{repr(self.expected)} not raised")
     if issubclass(exc_type, self.expected):
         self.value = exc_value
         return True
     return False
Пример #8
0
async def _slip39_show_share_words(ctx, share_index, share_words):
    first, chunks, last = _slip39_split_share_into_pages(share_words)

    if share_index is None:
        header_title = "Recovery seed"
    else:
        header_title = "Recovery share #%s" % (share_index + 1)
    header_icon = ui.ICON_RESET
    pages = []  # ui page components
    shares_words_check = []  # check we display correct data

    # first page
    text = Text(header_title, header_icon)
    text.bold("Write down these")
    text.bold("%s words:" % len(share_words))
    text.br_half()
    for index, word in first:
        text.mono("%s. %s" % (index + 1, word))
        shares_words_check.append(word)
    pages.append(text)

    # middle pages
    for chunk in chunks:
        text = Text(header_title, header_icon)
        for index, word in chunk:
            text.mono("%s. %s" % (index + 1, word))
            shares_words_check.append(word)
        pages.append(text)

    # last page
    text = Text(header_title, header_icon)
    for index, word in last:
        text.mono("%s. %s" % (index + 1, word))
        shares_words_check.append(word)
    text.br_half()
    text.bold("I confirm that I wrote")
    text.bold("down all %s words." % len(share_words))
    pages.append(text)

    # pagination
    paginated = Paginated(pages)

    if __debug__:

        word_pages = [first] + chunks + [last]

        def export_displayed_words():
            # export currently displayed mnemonic words into debuglink
            debug.reset_current_words = [
                w for _, w in word_pages[paginated.page]
            ]

        paginated.on_change = export_displayed_words
        export_displayed_words()

    # make sure we display correct data
    utils.ensure(share_words == shares_words_check)

    # confirm the share
    await hold_to_confirm(ctx, paginated)  # TODO: customize the loader here
Пример #9
0
def _build_key(
    secret: bytes,
    discriminator: bytes,
    index: int | None = None,
    out: bytes | None = None,
) -> bytes:
    """
    Creates an unique-purpose key
    """

    key_buff = _BUILD_KEY_BUFFER
    utils.ensure(len(secret) == _SECRET_LENGTH, "Invalid key length")
    utils.ensure(len(discriminator) <= _DISCRIMINATOR_LENGTH, "Disc too long")

    offset = _SECRET_LENGTH
    utils.memcpy(key_buff, 0, secret, 0, _SECRET_LENGTH)

    for i in range(_SECRET_LENGTH, len(key_buff)):
        key_buff[i] = 0

    utils.memcpy(key_buff, offset, discriminator, 0, len(discriminator))
    offset += _DISCRIMINATOR_LENGTH  # fixed domain separator size

    if index is not None:
        # dump_uvarint_b_into, saving import
        shifted = True
        while shifted:
            shifted = index >> 7
            key_buff[offset] = (index & 0x7F) | (0x80 if shifted else 0x00)
            offset += 1
            index = shifted

    return crypto_helpers.keccak_2hash(key_buff, out)
Пример #10
0
 def add(self, multisig: MultisigRedeemScriptType):
     fp = multisig_fingerprint(multisig)
     ensure(fp is not None)
     if self.fingerprint is None:
         self.fingerprint = fp
     elif self.fingerprint != fp:
         self.mismatch = True
Пример #11
0
def write_uint32_be(w: Writer, n: int) -> int:
    ensure(0 <= n <= 0xFFFFFFFF)
    w.append((n >> 24) & 0xFF)
    w.append((n >> 16) & 0xFF)
    w.append((n >> 8) & 0xFF)
    w.append(n & 0xFF)
    return 4
Пример #12
0
def _build_key(secret,
               discriminator=None,
               index: int = None,
               out: bytes = None) -> bytes:
    """
    Creates an unique-purpose key
    """
    key_buff = BUILD_KEY_BUFFER  # bytearray(32 + 12 + 4)  # key + disc + index
    utils.ensure(len(secret) == 32, "Invalid key length")
    utils.ensure(len(discriminator) <= 12, "Disc too long")

    offset = 32
    utils.memcpy(key_buff, 0, secret, 0, 32)

    for i in range(32, len(key_buff)):
        key_buff[i] = 0

    if discriminator is not None:
        utils.memcpy(key_buff, offset, discriminator, 0, len(discriminator))
        offset += len(discriminator)

    if index is not None:
        # dump_uvarint_b_into, saving import
        shifted = True
        while shifted:
            shifted = index >> 7
            key_buff[offset] = (index & 0x7F) | (0x80 if shifted else 0x00)
            offset += 1
            index = shifted

    return crypto.keccak_2hash(key_buff, out)
Пример #13
0
 def get(self,
         key: int,
         default: T | None = None) -> bytes | T | None:  # noqa: F811
     utils.ensure(key < len(self.fields), f"failed to load key {key}")
     if self.data[key][0] != 1:
         return default
     return bytes(self.data[key][1:])
Пример #14
0
    def __init__(self, tx: SignTx, keychain: seed.Keychain,
                 coin: coininfo.CoinInfo) -> None:
        ensure(coin.decred)
        super().__init__(tx, keychain, coin)

        self.write_tx_header(self.serialized_tx, self.tx, witness_marker=True)
        write_bitcoin_varint(self.serialized_tx, self.tx.inputs_count)
Пример #15
0
def _rsig_process_bp(state: State, rsig_data: MoneroTransactionRsigData):
    from apps.monero.xmr import range_signatures
    from apps.monero.xmr.serialize_messages.tx_rsig_bulletproof import (
        Bulletproof,
        BulletproofPlus,
    )

    if state.rsig_is_bp_plus:
        bp_obj = serialize.parse_msg(rsig_data.rsig, BulletproofPlus)
    else:
        bp_obj = serialize.parse_msg(rsig_data.rsig, Bulletproof)
    rsig_data.rsig = None

    # BP is hashed with raw=False as hash does not contain L, R
    # array sizes compared to the serialized bulletproof format
    # thus direct serialization cannot be used.
    state.full_message_hasher.rsig_val(bp_obj, raw=False)
    res = range_signatures.verify_bp(bp_obj, state.output_amounts,
                                     state.output_masks)
    utils.ensure(res, "BP verification fail")
    state.mem_trace("BP verified" if __debug__ else None, collect=True)
    del (bp_obj, range_signatures)

    # State cleanup after verification is finished
    state.output_amounts = []
    state.output_masks = []
Пример #16
0
    def assertListEqual(self, x, y, msg=''):
        if len(x) != len(y):
            if not msg:
                msg = "List lengths not equal"
            ensure(False, msg)

        for i in range(len(x)):
            self.assertEqual(x[i], y[i], msg)
Пример #17
0
    def assertEqual(self, x, y, msg=''):
        if not msg:
            msg = f"{repr(x)} vs (expected) {repr(y)}"

        if x.__class__ == y.__class__ and x.__class__.__name__ == "Msg":
            self.assertMessageEqual(x, y)
        else:
            ensure(x == y, msg)
Пример #18
0
def output_script_p2sh(scripthash: bytes) -> bytearray:
    # A9 14 <scripthash> 87
    utils.ensure(len(scripthash) == 20)
    s = bytearray(23)
    s[0] = 0xA9  # OP_HASH_160
    s[1] = 0x14  # pushing 20 bytes
    s[2:22] = scripthash
    s[22] = 0x87  # OP_EQUAL
    return s
Пример #19
0
def check_script_size(script: bytes) -> None:
    try:
        r = BufferReader(script)
        n = read_uint32_be(r)
        r.read(n)
        n = read_uint32_be(r)
        ensure(r.remaining_count() == n)
    except (AssertionError, EOFError):
        raise wire.DataError("Invalid script")
Пример #20
0
def _check_out_commitment(state: State, amount, mask, C):
    utils.ensure(
        crypto.point_eq(
            C,
            crypto.point_add(crypto.scalarmult_base(mask),
                             crypto.scalarmult_h(amount)),
        ),
        "OutC fail",
    )
Пример #21
0
 def assertRaises(self, exc, func=None, *args, **kwargs):
     if func is None:
         return AssertRaisesContext(exc)
     try:
         func(*args, **kwargs)
         ensure(False, "%r not raised" % exc)
     except Exception as e:
         if isinstance(e, exc):
             return
         raise
Пример #22
0
def output_script_p2pkh(pubkeyhash: bytes) -> bytearray:
    utils.ensure(len(pubkeyhash) == 20)
    s = bytearray(25)
    s[0] = 0x76  # OP_DUP
    s[1] = 0xA9  # OP_HASH_160
    s[2] = 0x14  # pushing 20 bytes
    s[3:23] = pubkeyhash
    s[23] = 0x88  # OP_EQUALVERIFY
    s[24] = 0xAC  # OP_CHECKSIG
    return s
Пример #23
0
def output_script_ssgen(pkh: bytes) -> bytearray:
    utils.ensure(len(pkh) == 20)
    s = bytearray(26)
    s[0] = 0xBB  # OP_SSGEN
    s[1] = 0x76  # OP_DUP
    s[2] = 0xA9  # OP_HASH160
    s[3] = 0x14  # OP_DATA_20
    s[4:24] = pkh
    s[24] = 0x88  # OP_EQUALVERIFY
    s[25] = 0xAC  # OP_CHECKSIG
    return s
Пример #24
0
def script_replay_protection_bip115(block_hash: bytes,
                                    block_height: bytes) -> bytearray:
    if block_hash is None or block_height is None:
        return bytearray()
    ensure(len(block_hash) == 32)
    s = bytearray(33)
    s[0] = 0x20  # 32 bytes for block hash
    s[1:33] = block_hash  # block hash
    write_scriptnum(s, block_height)
    s.append(0xB4)  # OP_CHECKBLOCKATHEIGHT
    return s
Пример #25
0
def write_uint64_be(w: Writer, n: int) -> int:
    ensure(0 <= n <= 0xFFFFFFFFFFFFFFFF)
    w.append((n >> 56) & 0xFF)
    w.append((n >> 48) & 0xFF)
    w.append((n >> 40) & 0xFF)
    w.append((n >> 32) & 0xFF)
    w.append((n >> 24) & 0xFF)
    w.append((n >> 16) & 0xFF)
    w.append((n >> 8) & 0xFF)
    w.append(n & 0xFF)
    return 8
Пример #26
0
def input_script_p2wpkh_in_p2sh(pubkeyhash: bytes) -> bytearray:
    # 16 00 14 <pubkeyhash>
    # Signature is moved to the witness.
    utils.ensure(len(pubkeyhash) == 20)

    w = empty_bytearray(3 + len(pubkeyhash))
    w.append(0x16)  # length of the data
    w.append(0x00)  # witness version byte
    w.append(0x14)  # P2WPKH witness program (pub key hash length)
    write_bytes_fixed(w, pubkeyhash, 20)  # pub key hash
    return w
Пример #27
0
    def preimage_hash(
        self,
        coin: CoinInfo,
        tx: SignTx,
        txi: TxInputType,
        pubkeyhash: bytes,
        sighash: int,
    ) -> bytes:
        h_preimage = HashWriter(
            blake2b(outlen=32,
                    personal=b"ZcashSigHash" +
                    struct.pack("<I", self.branch_id)))

        ensure(coin.overwintered)
        ensure(tx.version == 4)

        write_uint32(h_preimage,
                     tx.version | OVERWINTERED)  # 1. nVersion | fOverwintered
        write_uint32(h_preimage, tx.version_group_id)  # 2. nVersionGroupId
        # 3. hashPrevouts
        write_bytes_fixed(h_preimage, bytearray(self.get_prevouts_hash()),
                          TX_HASH_SIZE)
        # 4. hashSequence
        write_bytes_fixed(h_preimage, bytearray(self.get_sequence_hash()),
                          TX_HASH_SIZE)
        # 5. hashOutputs
        write_bytes_fixed(h_preimage, bytearray(self.get_outputs_hash()),
                          TX_HASH_SIZE)

        zero_hash = b"\x00" * TX_HASH_SIZE
        write_bytes_fixed(h_preimage, zero_hash,
                          TX_HASH_SIZE)  # 6. hashJoinSplits
        write_bytes_fixed(h_preimage, zero_hash,
                          TX_HASH_SIZE)  # 7. hashShieldedSpends
        write_bytes_fixed(h_preimage, zero_hash,
                          TX_HASH_SIZE)  # 8. hashShieldedOutputs

        write_uint32(h_preimage, tx.lock_time)  # 9. nLockTime
        write_uint32(h_preimage, tx.expiry)  # 10. expiryHeight
        write_uint64(h_preimage, 0)  # 11. valueBalance
        write_uint32(h_preimage, sighash)  # 12. nHashType

        write_bytes_reversed(h_preimage, txi.prev_hash,
                             TX_HASH_SIZE)  # 13a. outpoint
        write_uint32(h_preimage, txi.prev_index)

        script_code = derive_script_code(txi, pubkeyhash)  # 13b. scriptCode
        write_bytes_prefixed(h_preimage, script_code)

        write_uint64(h_preimage, txi.amount)  # 13c. value

        write_uint32(h_preimage, txi.sequence)  # 13d. nSequence

        return get_tx_hash(h_preimage)
Пример #28
0
def output_script_native_p2wpkh_or_p2wsh(witprog: bytes) -> bytearray:
    # Either:
    # 00 14 <20-byte-key-hash>
    # 00 20 <32-byte-script-hash>
    ensure(len(witprog) == 20 or len(witprog) == 32)

    w = empty_bytearray(3 + len(witprog))
    w.append(0x00)  # witness version byte
    w.append(len(witprog))  # pub key hash length is 20 (P2WPKH) or 32 (P2WSH) bytes
    write_bytes(w, witprog)  # pub key hash
    return w
Пример #29
0
    def __init__(
        self,
        tx: SignTx,
        keychain: Keychain,
        coin: CoinInfo,
        approver: approvers.Approver,
    ) -> None:
        ensure(coin.overwintered)
        super().__init__(tx, keychain, coin, approver)

        if tx.version != 4:
            raise wire.DataError("Unsupported transaction version.")
Пример #30
0
    def __init__(self, tx: SignTx, keychain: Keychain, coin: CoinInfo) -> None:
        ensure(coin.overwintered)
        super().__init__(tx, keychain, coin)

        if self.tx.version == 3:
            if not self.tx.branch_id:
                self.tx.branch_id = 0x5BA81B19  # Overwinter
        elif self.tx.version == 4:
            if not self.tx.branch_id:
                self.tx.branch_id = 0x76B809BB  # Sapling
        else:
            raise wire.DataError("Unsupported version for overwintered transaction")