Example #1
0
    def test_compression(self):
        prv, pub = generate_keypair()

        encoded = pub.encode(compressed=True)
        self.assertEqual(PublicKey.decode(encoded), pub)

        encoded = pub.encode(compressed=False)
        self.assertEqual(PublicKey.decode(encoded), pub)
    def test_digest_p2sh_p2wpkh(self):
        # https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#p2sh-p2wpkh
        tx = Transaction.from_hex(
            '0100000001db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a54770100000000feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac0008af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac92040000'
        )
        ref = Output(
            10 * 10**8,
            hex_to_bytes('a9144733f37cf4db86fbc2efed2500b4f4e49f31202387'))

        inp = tx.inputs[0]
        inp._referenced_output = ref
        inp.script = serialize(
            hex_to_bytes('001479091972186c449eb1ded22b78e40d009bdf0089'))

        sighash = tx.sighash(0)
        self.assertEqual(
            bytes_to_hex(sighash),
            '64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6')
        sig = Signature.from_hex(
            '3044022047ac8e878352d3ebbde1c94ce3a10d057c24175747116f8288e5d794d12d482f0220217f36a485cae903c713331d877c1f64677e3622ad4010726870540656fe9dcb'
        )
        pub = PublicKey.from_hex(
            '03ad1d8e89212f0b92c74d23bb710c00662ad1470198ac48c43f7d6f93a2a26873'
        )

        self.assertTrue(sig.verify_hash(sighash, pub))
Example #3
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)
Example #4
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))
Example #5
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)
Example #6
0
 def test_p2wpkh(self):
     """https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#examples"""
     pubkey = PublicKey.from_hex(
         '0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798'
     )
     self.assertEqual(
         bech32.encode(self.hrp, self.witver,
                       hash160(pubkey.encode(compressed=True))),
         'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4')
     address = pubkey_to_address(pubkey, version='P2WPKH')
     self.assertEqual(address, 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4')
     self.assertEqual(address_type(address), ADDRESS.P2WPKH)
Example #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])
Example #8
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)
                    break
            else:
                valid_signatures.append(False)

        self.push(sum(valid_signatures) >= m)
    def test_digest_p2wpkh(self):
        # https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#native-p2wpkh
        tx = Transaction.from_hex(
            '0100000002fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f0000000000eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac11000000'
        )
        ref = Output(
            6 * 10**8,
            hex_to_bytes('00141d0f172a0ecb48aee1be1f2687d2963ae33f71a1'))

        tx.inputs[1]._referenced_output = ref

        sighash = sha256(sha256(tx.signature_form_segwit(1)))

        self.assertEqual(
            bytes_to_hex(sighash),
            'c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670')
        public = PublicKey.from_hex(
            '025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357'
        )

        sig = Signature.from_hex(
            '304402203609e17b84f6a7d30c80bfa610b5b4542f32a8a0d5447a12fb1366d7f01cc44a0220573a954c4518331561406f90300e8f3358f51928d43c212a8caed02de67eebee'
        )
        self.assertTrue(sig.verify_hash(sighash, public))
Example #10
0
def pubkey_to_bech32(pub: PublicKey, witver: int) -> str:
    """https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#witness-program"""
    witprog = hash160(pub.encode(compressed=True))
    return bech32.encode(network('hrp'), witver, witprog)