예제 #1
0
def parse_output_script_multisig(script: bytes) -> Tuple[List[bytes], int]:
    try:
        r = BytearrayReader(script)

        threshold = r.get() - 0x50
        pubkey_count = script[-2] - 0x50

        if (not 1 <= threshold <= 15 or not 1 <= pubkey_count <= 15
                or threshold > pubkey_count):
            raise ValueError

        public_keys = []
        for i in range(pubkey_count):
            n = read_op_push(r)
            if n != 33:
                raise ValueError
            public_keys.append(r.read(n))

        r.get()  # ignore pubkey_count
        if r.get() != 0xAE:  # OP_CHECKMULTISIG
            raise ValueError
        if r.remaining_count():
            raise ValueError

    except (ValueError, IndexError):
        raise wire.DataError("Invalid multisig script")

    return public_keys, threshold
예제 #2
0
def parse_input_script_p2pkh(script_sig: bytes, ) -> Tuple[bytes, bytes, int]:
    try:
        r = BytearrayReader(script_sig)
        n = read_op_push(r)
        signature = r.read(n - 1)
        hash_type = r.get()

        n = read_op_push(r)
        pubkey = r.read()
        if len(pubkey) != n:
            raise ValueError
    except (ValueError, IndexError):
        wire.DataError("Invalid scriptSig.")

    return pubkey, signature, hash_type
예제 #3
0
def decode_seq(data: bytes) -> List[bytes]:
    r = BytearrayReader(data)

    if r.get() != 0x30:
        raise ValueError
    n = decode_length(r)

    seq = []
    end = r.offset + n
    while r.offset < end:
        i = decode_int(r)
        seq.append(i)

    if r.offset != end or r.remaining_count():
        raise ValueError

    return seq
예제 #4
0
def decode_length(r: BytearrayReader) -> int:
    init = r.get()
    if init < 0x80:
        # short form encodes length in initial octet
        return init

    if init == 0x80 or init == 0xFF or r.peek() == 0x00:
        raise ValueError  # indefinite length, RFU or not shortest possible

    # long form
    n = 0
    for _ in range(init & 0x7F):
        n = n * 0x100 + r.get()

    if n < 128:
        raise ValueError  # encoding is not the shortest possible

    return n
예제 #5
0
def verify_nonownership(
    proof: bytes,
    script_pubkey: bytes,
    commitment_data: bytes,
    keychain: seed.Keychain,
    coin: CoinInfo,
) -> bool:
    try:
        r = BytearrayReader(proof)
        if r.read(4) != _VERSION_MAGIC:
            raise wire.DataError("Unknown format of proof of ownership")

        flags = r.get()
        if flags & 0b1111_1110:
            raise wire.DataError("Unknown flags in proof of ownership")

        # Determine whether our ownership ID appears in the proof.
        id_count = read_bitcoin_varint(r)
        ownership_id = get_identifier(script_pubkey, keychain)
        not_owned = True
        for _ in range(id_count):
            if utils.consteq(ownership_id, r.read(_OWNERSHIP_ID_LEN)):
                not_owned = False

        # Verify the BIP-322 SignatureProof.

        proof_body = proof[:r.offset]
        sighash = hashlib.sha256(proof_body)
        sighash.update(script_pubkey)
        sighash.update(commitment_data)
        script_sig, witness = read_bip322_signature_proof(r)

        # We don't call verifier.ensure_hash_type() to avoid possible compatibility
        # issues between implementations, because the hash type doesn't influence
        # the digest and the value to use is not defined in BIP-322.
        verifier = SignatureVerifier(script_pubkey, script_sig, witness, coin)
        verifier.verify(sighash.digest())
    except (ValueError, IndexError):
        raise wire.DataError("Invalid proof of ownership")

    return not_owned
예제 #6
0
def parse_witness_multisig(
        witness: bytes) -> Tuple[bytes, List[Tuple[bytes, int]]]:
    try:
        r = BytearrayReader(witness)

        # Get number of witness stack items.
        item_count = read_bitcoin_varint(r)

        # Skip over OP_FALSE, which is due to the old OP_CHECKMULTISIG bug.
        if r.get() != 0:
            raise ValueError

        signatures = []
        for i in range(item_count - 2):
            n = read_bitcoin_varint(r)
            signature = r.read(n - 1)
            hash_type = r.get()
            signatures.append((signature, hash_type))

        script = read_bytes_prefixed(r)
        if r.remaining_count():
            raise ValueError
    except (ValueError, IndexError):
        raise wire.DataError("Invalid witness.")

    return script, signatures
예제 #7
0
def read_op_push(r: BytearrayReader) -> int:
    prefix = r.get()
    if prefix < 0x4C:
        n = prefix
    elif prefix == 0x4C:
        n = r.get()
    elif prefix == 0x4D:
        n = r.get()
        n += r.get() << 8
    elif prefix == 0x4E:
        n = r.get()
        n += r.get() << 8
        n += r.get() << 16
        n += r.get() << 24
    else:
        raise ValueError
    return n
예제 #8
0
def decode_int(r: BytearrayReader) -> bytes:
    if r.get() != 0x02:
        raise ValueError

    n = decode_length(r)
    if n == 0:
        raise ValueError

    if r.peek() & 0x80:
        raise ValueError  # negative integer

    if r.peek() == 0x00 and n > 1:
        r.get()
        n -= 1
        if r.peek() & 0x80 == 0x00:
            raise ValueError  # excessive zero-padding

        if r.peek() == 0x00:
            raise ValueError  # excessive zero-padding

    return r.read(n)
예제 #9
0
def parse_witness_p2wpkh(witness: bytes) -> Tuple[bytes, bytes, int]:
    try:
        r = BytearrayReader(witness)

        if r.get() != 2:
            # num of stack items, in P2WPKH it's always 2
            raise ValueError

        n = read_bitcoin_varint(r)
        signature = r.read(n - 1)
        hash_type = r.get()

        pubkey = read_bytes_prefixed(r)
        if r.remaining_count():
            raise ValueError
    except (ValueError, IndexError):
        raise wire.DataError("Invalid witness.")

    return pubkey, signature, hash_type
예제 #10
0
def parse_input_script_multisig(
    script_sig: bytes, ) -> Tuple[bytes, List[Tuple[bytes, int]]]:
    try:
        r = BytearrayReader(script_sig)

        # Skip over OP_FALSE, which is due to the old OP_CHECKMULTISIG bug.
        if r.get() != 0:
            raise ValueError

        signatures = []
        n = read_op_push(r)
        while r.remaining_count() > n:
            signature = r.read(n - 1)
            hash_type = r.get()
            signatures.append((signature, hash_type))
            n = read_op_push(r)

        script = r.read()
        if len(script) != n:
            raise ValueError
    except (ValueError, IndexError):
        raise wire.DataError("Invalid scriptSig.")

    return script, signatures
예제 #11
0
def read_bytes_prefixed(r: BytearrayReader) -> bytes:
    n = read_bitcoin_varint(r)
    return r.read(n)
예제 #12
0
def read_bip322_signature_proof(r: BytearrayReader) -> Tuple[bytes, bytes]:
    script_sig = read_bytes_prefixed(r)
    witness = r.read()
    return script_sig, witness