Esempio n. 1
0
    def child(self, i: int) -> 'Xpub':
        hardened = i >= 1 << 31

        if hardened:
            raise KeyDerivationError(
                'Cannot derive a hardened key from an extended public key')

        I = hmac.new(key=self.code,
                     msg=self.keydata() + int_to_bytes(i).rjust(4, b'\x00'),
                     digestmod=hashlib.sha512).digest()

        I_L, I_R = I[:32], I[32:]

        key = PrivateKey(I_L).to_public().point + self.key.point
        ret_code = I_R
        path = self.path + f'/{i}'

        # TODO add point at infinity check
        return Xpub(PublicKey(key),
                    ret_code,
                    depth=self.depth + 1,
                    i=i,
                    parent=self.fingerprint(),
                    path=path,
                    addresstype=self.type.value)
Esempio n. 2
0
    def OP_CHECKSIG(self):
        """https://en.bitcoin.it/wiki/OP_CHECKSIG"""
        pub = PublicKey.decode(self.pop())
        extended_sig = self.pop()
        sig = Signature.decode(extended_sig[:-1])
        hashcode = SIGHASH(extended_sig[-1])

        sighash = self.tx.sighash(i=self.index, hashcode=hashcode)
        self.push(sig.verify_hash(sighash, pub))
Esempio n. 3
0
    def test_verification(self):
        for vector in self.vectors:

            try:
                sig = Schnorr.from_hex(vector['sig'])
                pubkey = PublicKey.from_hex(vector['pub'])
                result = vector['msg'].verify(signature=sig, public=pubkey)
            except AssertionError:
                result = False

            self.assertEqual(result, vector['result'])
Esempio n. 4
0
 def test_p2wsh(self):
     """https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#examples"""
     pubkey = PublicKey.from_hex(
         '0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798'
     )
     script = push(pubkey.encode(
         compressed=True)) + OP.CHECKSIG.byte  # <key> <OP_CHECKSIG>
     address = script_to_address(script, 'P2WSH')
     self.assertEqual(
         address,
         'bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3')
     self.assertEqual(address_type(address), ADDRESS.P2WSH)
Esempio n. 5
0
    def test_encoding(self):
        for vector in self.vectors:
            prv_hex = vector['prv']
            if not prv_hex:
                continue

            prv = PrivateKey.from_hex(prv_hex)
            pubkey_actual = prv.to_public()
            pubkey = PublicKey.from_hex(vector['pub'])

            self.assertEqual(pubkey_actual.hex(compact=True),
                             pubkey.hex(compact=True))

            msg = vector['msg']
            aux = vector['aux']
            signature = msg.sign_schnorr(prv, aux=aux)
            self.assertEqual(signature.hex(), vector['sig'].lower())
Esempio n. 6
0
    def OP_CHECKMULTISIG(self):
        # Multisig m out of n
        # The stack at this point should look something like this
        # ['',
        #  '3045022100c38f1d0e340f4308b7f6e4bef0c8668e84793370924844a1076cc986f37047af02207cc29b61e85dc580ce85e01858e2e47eb3b8a80472ad784eb74538045e8172e801',
        #  '30450221009a6abea495730976b69f255282ee0c488e49769138b7048e749dd5215bdf8120022069f690fcaf5dba05f0537911b16b2868087440eb55a19dc6e89bcb83f1f35c6501',
        #  2,
        #  '02d271610ba72d9b0948ea0821fac77e0e6d10234a266b4828671a86a59073bb30',
        #  '0359446555d1c389782468191250c007a98393eb6e9db64649cd7ed1e7f9ca0cf3',
        #  '023779ee80b4a940503b1d630e7a3934503eecba5d571111f30841cdfbce0e8397',
        #  3]

        n = self.pop()
        keys = [PublicKey.decode(self.pop()) for _ in range(n)]

        m = self.pop()
        raw_signatures = [self.pop() for _ in range(m)]

        _ = self.pop(
        )  # extra bytes in stack due to original implementation bug

        valid_signatures = []
        for raw_sig in raw_signatures:
            sig, hashcode = Signature.decode(raw_sig[:-1]), SIGHASH(
                raw_sig[-1])
            sighash = self.tx.sighash(self.index,
                                      script=self.scriptPubKey,
                                      hashcode=hashcode)
            for pub in keys:
                valid = sig.verify_hash(sighash, pub)
                if valid:
                    valid_signatures.append(valid)
                    keys.remove(
                        pub
                    )  # Drop public key, to avoid allowing multiple signatures with same key
                    break
            else:
                valid_signatures.append(False)

        self.push(sum(valid_signatures) >= m)
Esempio n. 7
0
    def deserialize(cls, bts: bytes) -> 'ExtendedKey':
        def read(n):
            nonlocal bts
            data, bts = bts[:n], bts[n:]
            return data

        net = read(4)
        is_private = net in network('extended_prv').values()
        is_public = net in network('extended_pub').values()
        assert is_public ^ is_private, f'Invalid network bytes : {bytes_to_hex(net)}'
        address_lookup = {
            val: key
            for key, val in (network('extended_prv') if is_private else
                             network('extended_pub')).items()
        }
        constructor = Xprv if is_private else Xpub
        depth = bytes_to_int(read(1))
        assert depth in range(256), f'Invalid depth : {depth}'
        fingerprint = read(4)
        i = bytes_to_int(read(4))
        if depth == 0:
            i = None
            path = None
        else:
            ih = f'{i}' if i < 2**31 else f"{i - 2**31}h"
            path = '/'.join([constructor.root_path] +
                            ['x' for _ in range(depth - 1)] + [ih])

        code = read(32)
        key = read(33)
        key = PrivateKey(key) if is_private else PublicKey.decode(key)
        assert not bts, 'Leftover bytes'
        return constructor(key,
                           code,
                           depth=depth,
                           i=i,
                           parent=fingerprint,
                           path=path,
                           addresstype=address_lookup[net])