Ejemplo 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)
Ejemplo n.º 2
0
    def test_signing(self):
        tx_ids = [
            'f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16',
            '12b5633bad1f9c167d523ad1aa1947b2732a865bf5414eab2f9e5ae5d5c191ba',  # P2PK
            # 'a38d3393a32d06fe842b35ebd68aa2b6a1ccbabbbc244f67462a10fd8c81dba5',  # coinbase
            'a8d60051745755be5b13ba3ecedc1540fbb66e95ab15e76b4d871fd7c2b68794',  # segwit
            'fff2525b8931402dd09222c50775608f75787bd2b87e56995a7bdd30f79702c4',
            'ee475443f1fbfff84ffba43ba092a70d291df233bd1428f3d09f7bd1a6054a1f',
            '7edb32d4ffd7a385b763c7a8e56b6358bcd729e747290624e18acdbe6209fc45',  # 1-of-1 multisig
            '001bf3d87e417c63eee64bd466d0a6eec9770a3b336368062e9db730cf5db922',  # Spends P2SH 2-of-3 multisig
            '5a0ce1166ff8e6800416b1aa25f1577e233f230bd21204a6505fa6ee5a9c5fc6',
            'ef27d32f7f0c645daec3071c203399783555d84cfe92bfe61583a464a260df0b',  # 24 inputs 7 outputs
            '454e575aa1ed4427985a9732d753b37dc711675eb7c977637b1eea7f600ed214',  # sends to P2SH and P2WSH
            'eba5e1e668e0d47dc28c7fff686a7f680e334e1f9740fd90f0aed3d5e9c4114a',  # spends P2WSH
            'e5c95e9b3c8e81bf9fc4da9f069e5c40fa38cdcc0067b5706b517878298a6f7f',  # non standard sequence
            'e694da982e1a725e3524c622932f6159a328194a9201588783393c35ac852732'  # P2SH-P2WSH
        ]

        private = PrivateKey.random()

        for tx_id in tx_ids:
            tx = Transaction.get(tx_id)
            for inp in tx.inputs:
                if inp.ref().type() not in (TX.P2WSH, TX.P2SH):
                    self.assertTrue(inp.is_signed())
                    inp.clear()
                    self.assertFalse(inp.is_signed())
                    inp.sign(private)
                    self.assertTrue(inp.is_signed())
                    self.assertFalse(tx.verify(inp.tx_index))
Ejemplo n.º 3
0
    def child(self, i: int) -> 'Xprv':
        hardened = i >= 1 << 31

        if hardened:
            I = hmac.new(key=self.code,
                         msg=self.keydata() +
                         int_to_bytes(i).rjust(4, b'\x00'),
                         digestmod=hashlib.sha512).digest()
        else:
            I = hmac.new(key=self.code,
                         msg=self.key.to_public().encode(compressed=True) +
                         int_to_bytes(i).rjust(4, b'\x00'),
                         digestmod=hashlib.sha512).digest()

        I_L, I_R = bytes_to_int(I[:32]), I[32:]
        key = (I_L + self.key.int()) % CURVE.N
        if I_L >= CURVE.N or key == 0:
            return self.child(i + 1)
        ret_code = I_R
        if hardened:
            path = self.path + f'/{i - 2**31}h'
        else:
            path = self.path + f'/{i}'
        return Xprv(PrivateKey.from_int(key),
                    ret_code,
                    depth=self.depth + 1,
                    i=i,
                    parent=self.fingerprint(),
                    path=path,
                    addresstype=self.type.value)
Ejemplo n.º 4
0
    def test_wif(self):

        payload = {'Random': 'Random'}
        data = urllib.parse.urlencode(payload).encode('ascii')
        req = urllib.request.Request(self.url, data)

        with urllib.request.urlopen(req) as response:
            html = HtmlPrivKey()
            html.feed(response.read().decode('utf-8'))

        wif, private = html.wif, html.private

        my_private = PrivateKey.from_wif(wif)
        my_wif = PrivateKey.from_hex(private).wif()

        self.assertEqual(my_private.hex().lower(), private.lower())
        self.assertEqual(my_wif, wif)
Ejemplo n.º 5
0
 def from_seed(cls, seed: Union[bytes, str], addresstype='P2PKH') -> 'Xprv':
     if isinstance(seed, str):
         seed = hex_to_bytes(seed)
     assert 16 <= len(seed) <= 64, 'Seed should be between 128 and 512 bits'
     I = hmac.new(key=b"Bitcoin seed", msg=seed,
                  digestmod=hashlib.sha512).digest()
     I_L, I_R = I[:32], I[32:]
     if bytes_to_int(I_L) == 0 or bytes_to_int(I_L) > CURVE.N:
         raise KeyDerivationError
     key, code = PrivateKey(I_L), I_R
     return cls(key, code, addresstype=addresstype)
Ejemplo n.º 6
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())
Ejemplo n.º 7
0
    def test_p2pkh(self):
        """https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses#See_Also"""

        payload = {'Random': 'Random'}
        data = urllib.parse.urlencode(payload).encode('ascii')
        req = urllib.request.Request(self.url, data)

        with urllib.request.urlopen(req) as response:
            html = HtmlLegacyAddress()
            html.feed(response.read().decode('utf-8'))

        private, public, address = html.private, html.public, html.address

        my_pubkey = PrivateKey.from_hex(private).to_public()

        self.assertEqual(public.lower(), my_pubkey.hex())
        self.assertEqual(pubkey_to_address(my_pubkey), address)
        self.assertEqual(address_type(address), ADDRESS.P2PKH)
Ejemplo n.º 8
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])
Ejemplo n.º 9
0
    def test_compression(self):
        prv = PrivateKey.random()

        self.assertEqual(PrivateKey.from_wif(prv.wif(compressed=False)), prv)
        self.assertEqual(PrivateKey.from_wif(prv.wif(compressed=True)), prv)