Example #1
1
def test_crypto():
    pts = ((0x50863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352,
            0x2cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6),
           (0xa83b8de893467d3a88d959c0eb4032d9ce3bf80f175d4d9e75892a3ebb8ab7e5,
            0x370f723328c24b7a97fe34063ba68f253fb08f8645d7c8b9a4ff98e3c29e7f0d),
           (0xf680556678e25084a82fa39e1b1dfd0944f7e69fddaa4e03ce934bd6b291dca0,
            0x52c10b721d34447e173721fb0151c68de1106badb089fb661523b8302a9097f5),
           (0x241febb8e23cbd77d664a18f66ad6240aaec6ecdc813b088d5b901b2e285131f,
            0x513378d9ff94f8d3d6c420bd13981df8cd50fd0fbd0cb5afabb3e66f2750026d))

    for pt in pts:
        b = bytes([(pt[1] & 0x1) + 0x2]) + pt[0].to_bytes(32, 'big')
        b_full = bytes([0x04]) + pt[0].to_bytes(32, 'big') + pt[1].to_bytes(32, 'big')
        pk = PublicKey.from_bytes(b)
        assert pk.point.y == pt[1]
        assert b == pk.compressed_bytes
        assert b_full == bytes(pk)

        assert bytes(PublicKey.from_hex(pk.to_hex())) == b_full

    for i in range(10):
        pk = PrivateKey.from_random()
        assert PrivateKey.from_hex(pk.to_hex()).key == pk.key

    hd_priv = HDPrivateKey.master_key_from_entropy()[0]
    hd_priv2 = HDKey.from_hex(hd_priv.to_hex())
    hd_pub = hd_priv.public_key
    hd_pub2 = HDKey.from_hex(hd_pub.to_hex())

    assert isinstance(hd_priv2, HDPrivateKey)
    assert hd_priv2._key.key == hd_priv._key.key
    assert hd_priv2.chain_code == hd_priv.chain_code

    assert isinstance(hd_pub2, HDPublicKey)
    assert hd_pub2._key.point.x == hd_pub._key.point.x
    assert hd_pub2._key.point.y == hd_pub._key.point.y
    assert hd_pub2.chain_code == hd_pub.chain_code
Example #2
0
    def extract_sig_info(self):
        """ Returns the signature and corresponding public key.

        Returns:
            dict:
                Contains three keys:
                'hash_type': Integer
                'signature': The DER-encoded signature
                'public_key': The bytes corresponding the public key.
        """
        if len(self) != 2:
            raise TypeError("Script is not a P2PKH signature script")

        if not isinstance(self[0], bytes) or \
           not isinstance(self[1], bytes):
            raise TypeError(
                "Signature script must contain two push operations.")

        try:
            sig_bytes = self[0]
            hash_type = sig_bytes[-1]
            Signature.from_der(sig_bytes[:-1])
        except ValueError:
            raise TypeError("Signature does not appear to be valid")

        try:
            PublicKey.from_bytes(self[1])
        except ValueError:
            raise TypeError("Public key does not appear to be valid")

        return dict(hash_type=hash_type,
                    signature=sig_bytes,
                    public_key=self[1])
Example #3
0
    def extract_sig_info(self):
        """ Returns the signature and corresponding public key.

        Returns:
            dict:
                Contains three keys:
                'hash_type': Integer
                'signature': The DER-encoded signature
                'public_key': The bytes corresponding the public key.
        """
        if len(self) != 2:
            raise TypeError("Script is not a P2PKH signature script")

        if not isinstance(self[0], bytes) or \
           not isinstance(self[1], bytes):
            raise TypeError(
                "Signature script must contain two push operations.")

        try:
            sig_bytes = self[0]
            hash_type = sig_bytes[-1]
            Signature.from_der(sig_bytes[:-1])
        except ValueError:
            raise TypeError("Signature does not appear to be valid")

        try:
            PublicKey.from_bytes(self[1])
        except ValueError:
            raise TypeError("Public key does not appear to be valid")

        return dict(hash_type=hash_type,
                    signature=sig_bytes,
                    public_key=self[1])
    def _op_checksig(self):
        """ The entire transaction's outputs, inputs, and script (from
            the most recently-executed OP_CODESEPARATOR to the end) are
            hashed. The signature used by OP_CHECKSIG must be a valid
            signature for this hash and public key. If it is, 1 is
            returned, 0 otherwise.
        """
        self._check_stack_len(2)
        self._check_txn()

        pub_key_bytes = self._stack.pop()
        s = self._stack.pop()
        sig_der, hash_type = s[:-1], s[-1]

        pub_key = PublicKey.from_bytes(pub_key_bytes)
        sig = Signature.from_der(sig_der)

        txn_copy = self._txn._copy_for_sig(input_index=self._input_index,
                                           hash_type=hash_type,
                                           sub_script=self._sub_script)
        msg = bytes(txn_copy) + utils.pack_u32(hash_type)
        tx_digest = hashlib.sha256(msg).digest()

        verified = pub_key.verify(tx_digest, sig)

        self._stack.append(verified)
Example #5
0
    def _op_checksig(self):
        """ The entire transaction's outputs, inputs, and script (from
            the most recently-executed OP_CODESEPARATOR to the end) are
            hashed. The signature used by OP_CHECKSIG must be a valid
            signature for this hash and public key. If it is, 1 is
            returned, 0 otherwise.
        """
        self._check_stack_len(2)
        self._check_txn()

        pub_key_bytes = self._stack.pop()
        s = self._stack.pop()
        sig_der, hash_type = s[:-1], s[-1]

        pub_key = PublicKey.from_bytes(pub_key_bytes)
        sig = Signature.from_der(sig_der)

        txn_copy = self._txn._copy_for_sig(input_index=self._input_index,
                                           hash_type=hash_type,
                                           sub_script=self._sub_script)
        msg = bytes(txn_copy) + utils.pack_u32(hash_type)
        tx_digest = hashlib.sha256(msg).digest()

        verified = pub_key.verify(tx_digest, sig)

        self._stack.append(verified)
Example #6
0
def test_crypto():
    pts = (
        (0x50863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352,
         0x2cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6),
        (0xa83b8de893467d3a88d959c0eb4032d9ce3bf80f175d4d9e75892a3ebb8ab7e5,
         0x370f723328c24b7a97fe34063ba68f253fb08f8645d7c8b9a4ff98e3c29e7f0d),
        (0xf680556678e25084a82fa39e1b1dfd0944f7e69fddaa4e03ce934bd6b291dca0,
         0x52c10b721d34447e173721fb0151c68de1106badb089fb661523b8302a9097f5),
        (0x241febb8e23cbd77d664a18f66ad6240aaec6ecdc813b088d5b901b2e285131f,
         0x513378d9ff94f8d3d6c420bd13981df8cd50fd0fbd0cb5afabb3e66f2750026d))

    for pt in pts:
        b = bytes([(pt[1] & 0x1) + 0x2]) + pt[0].to_bytes(32, 'big')
        b_full = bytes([0x04]) + pt[0].to_bytes(32, 'big') + pt[1].to_bytes(
            32, 'big')
        pk = PublicKey.from_bytes(b)
        assert pk.point.y == pt[1]
        assert b == pk.compressed_bytes
        assert b_full == bytes(pk)

        assert bytes(PublicKey.from_hex(pk.to_hex())) == b_full

    for i in range(10):
        pk = PrivateKey.from_random()
        assert PrivateKey.from_hex(pk.to_hex()).key == pk.key

    hd_priv = HDPrivateKey.master_key_from_entropy()[0]
    hd_priv2 = HDKey.from_hex(hd_priv.to_hex())
    hd_pub = hd_priv.public_key
    hd_pub2 = HDKey.from_hex(hd_pub.to_hex())

    assert isinstance(hd_priv2, HDPrivateKey)
    assert hd_priv2._key.key == hd_priv._key.key
    assert hd_priv2.chain_code == hd_priv.chain_code

    assert isinstance(hd_pub2, HDPublicKey)
    assert hd_pub2._key.point.x == hd_pub._key.point.x
    assert hd_pub2._key.point.y == hd_pub._key.point.y
    assert hd_pub2.chain_code == hd_pub.chain_code
    def _op_checkmultisig(self, partial=False):
        """ Compares the first signature against each public key until
            it finds an ECDSA match. Starting with the subsequent public
            key, it compares the second signature against each remaining
            public key until it finds an ECDSA match. The process is
            repeated until all signatures have been checked or not enough
            public keys remain to produce a successful result. All
            signatures need to match a public key. Because public keys are
            not checked again if they fail any signature comparison,
            signatures must be placed in the scriptSig using the same
            order as their corresponding public keys were placed in the
            scriptPubKey or redeemScript. If all signatures are valid, 1
            is returned, 0 otherwise. Due to a bug, one extra unused value
            is removed from the stack.
        """
        self._check_stack_len(1)
        self._check_txn()

        num_keys = self._stack.pop()
        self._check_stack_len(num_keys)

        keys_bytes = []
        for i in range(num_keys):
            keys_bytes.insert(0, self._stack.pop())
        public_keys = [PublicKey.from_bytes(p) for p in keys_bytes]

        min_num_sigs = self._stack.pop()

        # Although "m" is the *minimum* number of required signatures, bitcoin
        # core only consumes "m" signatures and then expects an OP_0. This
        # means that if m < min_num_sigs <= n, bitcoin core will return a
        # script failure. See:
        # https://github.com/bitcoin/bitcoin/blob/0.10/src/script/interpreter.cpp#L840
        # We will do the same.
        hash_types = set()
        sigs = []
        for i in range(min_num_sigs):
            s = self._stack.pop()
            try:
                sig = Signature.from_der(s[:-1])
                hash_types.add(s[-1])
                sigs.insert(0, sig)
            except ValueError:
                if partial:
                    # Put it back on stack
                    self._stack.append(s)
                else:
                    # If not a partial evaluation there are not enough
                    # sigs
                    rv = False
                break

        if len(hash_types) != 1:
            raise ScriptInterpreterError(
                "Not all signatures have the same hash type!")

        hash_type = hash_types.pop()
        txn_copy = self._txn._copy_for_sig(input_index=self._input_index,
                                           hash_type=hash_type,
                                           sub_script=self._sub_script)

        msg = bytes(txn_copy) + utils.pack_u32(hash_type)
        txn_digest = hashlib.sha256(msg).digest()

        # Now we verify
        last_match = -1
        rv = True
        match_count = 0

        for sig in sigs:
            matched_any = False
            for i, pub_key in enumerate(public_keys[last_match + 1:]):
                if pub_key.verify(txn_digest, sig):
                    last_match = i
                    match_count += 1
                    matched_any = True
                    break

            if not matched_any:
                # Bail early if the sig couldn't be verified
                # by any public key
                rv = False
                break

        rv &= match_count >= min_num_sigs

        # Now make sure the last thing on the stack is OP_0
        if len(self._stack) == 1:
            rv &= self._stack.pop() == b''
            rv &= len(self._stack) == 0
        else:
            rv = False

        self._stack.append(rv)
        if partial:
            self.match_count = match_count
Example #8
0
    def _op_checkmultisig(self, partial=False):
        """ Compares the first signature against each public key until
            it finds an ECDSA match. Starting with the subsequent public
            key, it compares the second signature against each remaining
            public key until it finds an ECDSA match. The process is
            repeated until all signatures have been checked or not enough
            public keys remain to produce a successful result. All
            signatures need to match a public key. Because public keys are
            not checked again if they fail any signature comparison,
            signatures must be placed in the scriptSig using the same
            order as their corresponding public keys were placed in the
            scriptPubKey or redeemScript. If all signatures are valid, 1
            is returned, 0 otherwise. Due to a bug, one extra unused value
            is removed from the stack.
        """
        self._check_stack_len(1)
        self._check_txn()

        num_keys = self._stack.pop()
        self._check_stack_len(num_keys)

        keys_bytes = []
        for i in range(num_keys):
            keys_bytes.insert(0, self._stack.pop())
        public_keys = [PublicKey.from_bytes(p) for p in keys_bytes]

        min_num_sigs = self._stack.pop()

        # Although "m" is the *minimum* number of required signatures, bitcoin
        # core only consumes "m" signatures and then expects an OP_0. This
        # means that if m < min_num_sigs <= n, bitcoin core will return a
        # script failure. See:
        # https://github.com/bitcoin/bitcoin/blob/0.10/src/script/interpreter.cpp#L840
        # We will do the same.
        hash_types = set()
        sigs = []
        for i in range(min_num_sigs):
            s = self._stack.pop()
            try:
                sig = Signature.from_der(s[:-1])
                hash_types.add(s[-1])
                sigs.insert(0, sig)
            except ValueError:
                if partial:
                    # Put it back on stack
                    self._stack.append(s)
                else:
                    # If not a partial evaluation there are not enough
                    # sigs
                    rv = False
                break

        if len(hash_types) != 1:
            raise ScriptInterpreterError("Not all signatures have the same hash type!")

        hash_type = hash_types.pop()
        txn_copy = self._txn._copy_for_sig(input_index=self._input_index,
                                           hash_type=hash_type,
                                           sub_script=self._sub_script)

        msg = bytes(txn_copy) + utils.pack_u32(hash_type)
        txn_digest = hashlib.sha256(msg).digest()

        # Now we verify
        last_match = -1
        rv = True
        match_count = 0

        for sig in sigs:
            matched_any = False
            for i, pub_key in enumerate(public_keys[last_match+1:]):
                if pub_key.verify(txn_digest, sig):
                    last_match = i
                    match_count += 1
                    matched_any = True
                    break

            if not matched_any:
                # Bail early if the sig couldn't be verified
                # by any public key
                rv = False
                break

        rv &= match_count >= min_num_sigs

        # Now make sure the last thing on the stack is OP_0
        if len(self._stack) == 1:
            rv &= self._stack.pop() == b''
            rv &= len(self._stack) == 0
        else:
            rv = False

        self._stack.append(rv)
        if partial:
            self.match_count = match_count