def test_wif(self):
        # https://en.bitcoin.it/wiki/Wallet_import_format
        prvkey = 0xC28FCA386C7A227600B2FE50B7CAE11EC86D3BF1FBE471BE89827E19D72AA1D

        uncompressedKey = b'\x80' + prvkey.to_bytes(32, byteorder='big')
        uncompressedWIF = b'5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ'
        wif = b58encode_check(uncompressedKey)
        self.assertEqual(wif, uncompressedWIF)
        key = b58decode_check(uncompressedWIF)
        self.assertEqual(key, uncompressedKey)

        compressedKey = b'\x80' + prvkey.to_bytes(32,
                                                  byteorder='big') + b'\x01'
        compressedWIF = b'KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617'
        wif = b58encode_check(compressedKey)
        self.assertEqual(wif, compressedWIF)
        key = b58decode_check(compressedWIF)
        self.assertEqual(key, compressedKey)

        # string
        compressedWIF = 'KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617'
        key = b58decode_check(compressedWIF)
        self.assertEqual(key, compressedKey)

        # string with leading space
        compressedWIF = ' KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617'
        b58decode_check(compressedWIF)
        self.assertEqual(key, compressedKey)

        # string with trailing space
        compressedWIF = 'KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617 '
        b58decode_check(compressedWIF)
        self.assertEqual(key, compressedKey)
示例#2
0
def wif_from_prvkey(prvkey: int, compressed: bool) -> bytes:
    """private key to Wallet Import Format"""

    payload = b'\x80' + int2octets(prvkey, ec.psize)
    if compressed:
        payload += b'\x01'
    return b58encode_check(payload)
def bip32_crack(parent_xpub: bytes, child_xprv: bytes) -> bytes:
    parent_xpub = b58decode_check(parent_xpub, 78)
    assert parent_xpub[45] in (2, 3), "extended parent key is not a public one"

    child_xprv = b58decode_check(child_xprv, 78)
    assert child_xprv[45] == 0, "extended child key is not a private one"

    # check depth
    assert child_xprv[4] == parent_xpub[4]+1, "wrong child/parent depth relation"

    # check fingerprint
    Parent_bytes = parent_xpub[45:  ]
    assert child_xprv[ 5: 9] == h160(Parent_bytes)[:4], "not a child for the provided parent"

    # check normal derivation
    child_index  =  child_xprv[ 9:13]
    assert child_index[0] < 0x80, "hardened derivation"

    parent_xprv =   child_xprv[  : 4] # version
    parent_xprv += parent_xpub[ 4: 5] # depth
    parent_xprv += parent_xpub[ 5: 9] # parent pubkey fingerprint
    parent_xprv += parent_xpub[ 9:13] # child index

    parent_chain_code = parent_xpub[13:45]
    parent_xprv += parent_chain_code  # chain code

    h = HMAC(parent_chain_code, Parent_bytes + child_index, sha512).digest()
    offset = int.from_bytes(h[:32], 'big')
    child = int.from_bytes(child_xprv[46:], 'big')
    parent = (child - offset) % ec.n
    parent_bytes = b'\x00' + parent.to_bytes(32, 'big')
    parent_xprv += parent_bytes        # private key

    return b58encode_check(parent_xprv)
示例#4
0
def address_from_pubkey(Q: Point,
                        compressed: bool,
                        version: bytes = b'\x00') -> bytes:
    """Public key to (bytes) address"""

    pubkey = point2octets(ec, Q, compressed)

    # FIXME: this is mainnet only
    vh160 = version + h160(pubkey)
    return b58encode_check(vh160)
    def test_b58_exceptions(self):
        # int is not hex-string or bytes
        self.assertRaises(TypeError, b58encode_check, 3)

        encoded = b58encode_check(b"test")

        # unexpected decoded length
        wrong_length = len(encoded) - 1
        self.assertRaises(ValueError, b58decode_check, encoded, wrong_length)

        # checksum is invalid
        invalidChecksum = encoded[:-4] + b'1111'
        self.assertRaises(ValueError, b58decode_check, invalidChecksum, 4)
    def test_bip32_exceptions(self):
        mprv = b'xppp9s21ZrQH143K2oxHiQ5f7D7WYgXD9h6HAXDBuMoozDGGiYHWsq7TLBj2yvGuHTLSPCaFmUyN1v3fJRiY2A4YuNSrqQMPVLZKt76goL6LP7L'

        self.assertRaises(ValueError, bip32_ckd, mprv, 'invalid index')
        self.assertRaises(ValueError, bip32_ckd, mprv, 0x80000000)
        self.assertRaises(ValueError, bip32_ckd, mprv, "800000")
        self.assertRaises(ValueError, bip32_derive, mprv, '/1')
        self.assertRaises(TypeError, bip32_derive, mprv, 1)
        mprv = b'xprv9s21ZrQH143K2oxHiQ5f7D7WYgXD9h6HAXDBuMoozDGGiYHWsq7TLBj2yvGuHTLSPCaFmUyN1v3fJRiY2A4YuNSrqQMPVLZKt76goL6LP7L'
        self.assertRaises(ValueError, bip32_child_index, mprv)

        xkey = b'\x04\x88\xAD\xE5'  # invalid version
        xkey += b'\x00' * 74
        xkey = b58encode_check(xkey)
        self.assertRaises(ValueError, bip32_ckd, xkey, 0x80000000)
def bip32_master_prvkey_from_seed(bip32_seed: Union[str, bytes], version: bytes) -> bytes:
    """derive the master extended private key from the seed"""
    if type(bip32_seed) == str: # hex string
        bip32_seed = bytes.fromhex(bip32_seed)
    assert version in PRIVATE, "wrong version, master key must be private"

    # serialization data
    xmprv = version                             # version
    xmprv += b'\x00'                            # depth
    xmprv += b'\x00\x00\x00\x00'                # parent pubkey fingerprint
    xmprv += b'\x00\x00\x00\x00'                # child index

    # actual extended key (key + chain code) derivation
    hashValue = HMAC(b"Bitcoin seed", bip32_seed, sha512).digest()
    mprv = int_from_Scalar(ec, hashValue[:32])
    xmprv += hashValue[32:]                     # chain code
    xmprv += b'\x00' + mprv.to_bytes(32, 'big') # private key

    return b58encode_check(xmprv)
def bip32_mprv_from_seed(seed: octets, version: octets) -> bytes:
    """derive the master extended private key from the seed"""

    if isinstance(version, str):  # hex string
        version = bytes.fromhex(version)
    assert version in PRIVATE, "wrong version, master key must be private"

    # serialization data
    xmprv = version  # version
    xmprv += b'\x00'  # depth
    xmprv += b'\x00\x00\x00\x00'  # parent pubkey fingerprint
    xmprv += b'\x00\x00\x00\x00'  # child index

    # actual extended key (key + chain code) derivation
    if isinstance(seed, str):  # hex string
        seed = bytes.fromhex(seed)
    hd = HMAC(b"Bitcoin seed", seed, sha512).digest()
    mprv = octets2int(hd[:32])
    xmprv += hd[32:]  # chain code
    xmprv += b'\x00' + mprv.to_bytes(32, 'big')  # private key

    return b58encode_check(xmprv)
示例#9
0
def bip32_xpub_from_xprv(xprv: bytes) -> bytes:
    """Neutered Derivation (ND)
    
    Computation of the extended public key corresponding to an extended
    private key (“neutered” as it removes the ability to sign transactions)
    """
    xprv = b58decode_check(xprv, 78)
    assert xprv[45] == 0, "extended key is not a private one"

    i = PRIVATE.index(xprv[:4])

    # serialization data
    xpub = PUBLIC[i]  # version
    # unchanged serialization data
    xpub += xprv[4:5]  # depth
    xpub += xprv[5:9]  # parent pubkey fingerprint
    xpub += xprv[9:13]  # child index
    xpub += xprv[13:45]  # chain code

    p = xprv[46:]
    P = pointMultiply(ec, p, ec.G)
    xpub += bytes_from_Point(ec, P, True)  # public key
    return b58encode_check(xpub)
def bip32_ckd(xparentkey: octets, index: Union[octets, int]) -> bytes:
    """Child Key Derivation (CDK)

    Key derivation is normal if the extended parent key is public or
    child_index is less than 0x80000000.

    Key derivation is hardened if the extended parent key is private and
    child_index is not less than 0x80000000.
    """

    if isinstance(index, int):
        index = index.to_bytes(4, 'big')
    elif isinstance(index, str):  # hex string
        index = bytes.fromhex(index)

    if len(index) != 4:
        raise ValueError(f"a 4 bytes int is required, not {len(index)}")

    xparent = b58decode_check(xparentkey, 78)

    version = xparent[:4]

    # serialization data
    xkey = version  # version
    xkey += (xparent[4] + 1).to_bytes(1, 'big')  # (increased) depth

    if (version in PUBLIC):
        if xparent[45] not in (2, 3):  # not a compressed public key
            raise ValueError("version/key mismatch in extended parent key")
        Parent_bytes = xparent[45:]
        Parent = octets2point(ec, Parent_bytes)
        xkey += h160(Parent_bytes)[:4]  # parent pubkey fingerprint
        if index[0] >= 0x80:
            raise ValueError("no private/hardened derivation from pubkey")
        xkey += index  # child index
        parent_chain_code = xparent[13:45]  # normal derivation
        # actual extended key (key + chain code) derivation
        h = HMAC(parent_chain_code, Parent_bytes + index, sha512).digest()
        offset = int.from_bytes(h[:32], 'big')
        Offset = pointMult(ec, offset, ec.G)
        Child = ec.add(Parent, Offset)
        Child_bytes = point2octets(ec, Child, True)
        xkey += h[32:]  # chain code
        xkey += Child_bytes  # public key
    elif (version in PRIVATE):
        if xparent[45] != 0:  # not a private key
            raise ValueError("version/key mismatch in extended parent key")
        parent = int.from_bytes(xparent[46:], 'big')
        Parent = pointMult(ec, parent, ec.G)
        Parent_bytes = point2octets(ec, Parent, True)
        xkey += h160(Parent_bytes)[:4]  # parent pubkey fingerprint
        xkey += index  # child index
        # actual extended key (key + chain code) derivation
        parent_chain_code = xparent[13:45]
        if (index[0] < 0x80):  # normal derivation
            h = HMAC(parent_chain_code, Parent_bytes + index, sha512).digest()
        else:  # hardened derivation
            h = HMAC(parent_chain_code, xparent[45:] + index, sha512).digest()
        offset = int.from_bytes(h[:32], 'big')
        child = (parent + offset) % ec.n
        child_bytes = b'\x00' + child.to_bytes(32, 'big')
        xkey += h[32:]  # chain code
        xkey += child_bytes  # private key
    else:
        raise ValueError("invalid extended key version")

    return b58encode_check(xkey)
示例#11
0
def bip32_ckd(xparentkey: bytes, index: Union[bytes, int]) -> bytes:
    """Child Key Derivation (CDK)

    Key derivation is normal if the extended parent key is public or
    child_index is less than 0x80000000.
    
    Key derivation is hardened if the extended parent key is private and
    child_index is not less than 0x80000000.
    """

    if isinstance(index, int):
        index = index.to_bytes(4, 'big')
    elif isinstance(index, bytes):
        assert len(index) == 4
    else:
        raise TypeError("a 4 bytes int is required")

    xparent = b58decode_check(xparentkey, 78)

    version = xparent[:4]

    # serialization data
    xkey = version  # version
    xkey += (xparent[4] + 1).to_bytes(1, 'big')  # (increased) depth

    if (version in PUBLIC):
        assert xparent[45] in (2, 3), \
               "version/key mismatch in extended parent key"
        Parent_bytes = xparent[45:]
        Parent = tuple_from_Point(ec, Parent_bytes)
        xkey += h160(Parent_bytes)[:4]  # parent pubkey fingerprint
        assert index[0] < 0x80, \
               "no private/hardened derivation from pubkey"
        xkey += index  # child index
        parent_chain_code = xparent[13:45]  ## normal derivation
        # actual extended key (key + chain code) derivation
        h = HMAC(parent_chain_code, Parent_bytes + index, sha512).digest()
        offset = int.from_bytes(h[:32], 'big')
        Offset = ec.pointMultiply(offset, ec.G)
        Child = ec.pointAdd(Parent, Offset)
        Child_bytes = bytes_from_Point(ec, Child, True)
        xkey += h[32:]  # chain code
        xkey += Child_bytes  # public key
    elif (version in PRIVATE):
        assert xparent[45] == 0, "version/key mismatch in extended parent key"
        parent = int.from_bytes(xparent[46:], 'big')
        Parent = ec.pointMultiply(parent, ec.G)
        Parent_bytes = bytes_from_Point(ec, Parent, True)
        xkey += h160(Parent_bytes)[:4]  # parent pubkey fingerprint
        xkey += index  # child index
        # actual extended key (key + chain code) derivation
        parent_chain_code = xparent[13:45]
        if (index[0] < 0x80):  ## normal derivation
            h = HMAC(parent_chain_code, Parent_bytes + index, sha512).digest()
        else:  ## hardened derivation
            h = HMAC(parent_chain_code, xparent[45:] + index, sha512).digest()
        offset = int.from_bytes(h[:32], 'big')
        child = (parent + offset) % ec.order
        child_bytes = b'\x00' + child.to_bytes(32, 'big')
        xkey += h[32:]  # chain code
        xkey += child_bytes  # private key
    else:
        raise ValueError("invalid extended key version")

    return b58encode_check(xkey)
示例#12
0
def address_from_pubkey(pubkey: bytes, version: bytes = b'\x00') -> bytes:
    """Public key to (bytes) address"""
    # FIXME: this is mainnet only
    vh160 = version + h160(pubkey)
    return b58encode_check(vh160)
示例#13
0
def wif_from_prvkey(prvkey: PrivateKey, compressed: bool = True) -> bytes:
    """private key to Wallet Import Format"""

    payload = b'\x80' + bytes_from_Scalar(ec, prvkey)
    if compressed: payload += b'\x01'
    return b58encode_check(payload)
def address_from_pubkey_bytes(inp, version=b'\x00'):
    vh160 = version + hash160(inp)
    return b58encode_check(vh160)
print(
    "\n*** [5] First 4 bytes of the second SHA-256 hash used as address checksum:"
)
print(h2[:4].hex())

print("\n*** [6] checksum added at the end of extended key:")
addr = ExtKey + h2[:4]
print(addr.hex())

print("\n*** [7] Base58 encoding")
wif = b58encode(addr)
print(wif)
assert wif == b'KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617', "failure"
assert b58encode_check(
    ExtKey
) == b'KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617', "failure"

print("\n****** WIF to private key ******")

print("\n*** [1] Base58 WIF")
print(wif)
compressed = len(wif) - 51
print("compressed" if (compressed == 1) else "uncompressed")

print("\n*** [2] Base58 decoding")
addr = b58decode(wif)
print(addr.hex())

print("\n*** [3] Extended key (checksum verified)")
ExtKey, checksum = addr[:-4], addr[-4:]
示例#16
0
print(
    "\n*** [5] First 4 bytes of the second SHA-256 hash used as address checksum:"
)
print(h2[:4].hex())

print("\n*** [6] checksum added at the end of extended key:")
addr = ExtKey + h2[:4]
print(addr.hex())

print("\n*** [7] Base58 encoding")
wif = b58encode(addr)
print(wif)
assert wif == b'5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ', "failure"
assert b58encode_check(
    ExtKey
) == b'5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ', "failure"

print("\n****** WIF to private key ******")

print("\n*** [1] Base58 WIF")
print(wif)
compressed = len(wif) - 51
print("compressed" if (compressed == 1) else "uncompressed")

print("\n*** [2] Base58 decoding")
addr = b58decode(wif)
print(addr.hex())

print("\n*** [3] Extended key (checksum verified)")
ExtKey, checksum = addr[:-4], addr[-4:]
示例#17
0
child_number = b'\x00\x00\x00\x00'
# the fingerprint of the parent's public key (0x00000000 if master key)
fingerprint  = b'\x00\x00\x00\x00'
idf = depth + fingerprint + child_number

# master private key, master public key, chain code
hashValue = HMAC(b"Bitcoin seed", seed.to_bytes(seed_bytes, byteorder='big'), sha512).digest()
p_bytes = hashValue[:32]
p = int(p_bytes.hex(), 16) % ec.order
p_bytes = b'\x00' + p.to_bytes(32, byteorder='big')
P = ec.pointMultiply(p, ec.G)
P_bytes = bytes_from_Point(ec, P, True)
chain_code = hashValue[32:]

#extended keys
ext_prv = b58encode_check(xprv + idf + chain_code + p_bytes)
print("\nm")
print(ext_prv)
ext_pub = b58encode_check(xpub + idf + chain_code + P_bytes)
print("M")
print(ext_pub)
assert ext_prv == b"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi", "failure"
assert ext_pub == b"xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8", "failure"

# ==first (0) hardened child==
depth = b'\x01'
child_number = 0 + 0x80000000 #hardened
child_number = child_number.to_bytes(4, byteorder='big')
fingerprint = h160(P_bytes)[:4]
idf = depth + fingerprint + child_number
    def test_mainnet(self):
        # bitcoin core derivation style
        mprv = b'xprv9s21ZrQH143K2ZP8tyNiUtgoezZosUkw9hhir2JFzDhcUWKz8qFYk3cxdgSFoCMzt8E2Ubi1nXw71TLhwgCfzqFHfM5Snv4zboSebePRmLS'

        # m/0'/0'/463'
        addr1 = b'1DyfBWxhVLmrJ7keyiHeMbt7N3UdeGU4G5'
        indexes = [0x80000000, 0x80000000, 0x80000000 + 463]
        addr = address_from_xpub(
            bip32_xpub_from_xprv(bip32_derive(mprv, indexes)))
        self.assertEqual(addr, addr1)
        path = "m/0'/0'/463'"
        addr = address_from_xpub(bip32_xpub_from_xprv(bip32_derive(mprv,
                                                                   path)))
        self.assertEqual(addr, addr1)

        # m/0'/0'/267'
        addr2 = b'11x2mn59Qy43DjisZWQGRResjyQmgthki'
        indexes = [0x80000000, 0x80000000, 0x80000000 + 267]
        addr = address_from_xpub(
            bip32_xpub_from_xprv(bip32_derive(mprv, indexes)))
        self.assertEqual(addr, addr2)
        path = "m/0'/0'/267'"
        addr = address_from_xpub(bip32_xpub_from_xprv(bip32_derive(mprv,
                                                                   path)))
        self.assertEqual(addr, addr2)

        xkey_version = PRIVATE[0]
        seed = "bfc4cbaad0ff131aa97fa30a48d09ae7df914bcc083af1e07793cd0a7c61a03f65d622848209ad3366a419f4718a80ec9037df107d8d12c19b83202de00a40ad"
        seed = bytes.fromhex(seed)
        xprv = bip32_mprv_from_seed(seed, xkey_version)
        xpub = b'xpub661MyMwAqRbcFMYjmw8C6dJV97a4oLss6hb3v9wTQn2X48msQB61RCaLGtNhzgPCWPaJu7SvuB9EBSFCL43kTaFJC3owdaMka85uS154cEh'
        self.assertEqual(bip32_xpub_from_xprv(xprv), xpub)

        ind = [0, 0]
        addr = address_from_xpub(bip32_xpub_from_xprv(bip32_derive(xprv, ind)))
        self.assertEqual(addr, b'1FcfDbWwGs1PmyhMVpCAhoTfMnmSuptH6g')

        ind = [0, 1]
        addr = address_from_xpub(bip32_xpub_from_xprv(bip32_derive(xprv, ind)))
        self.assertEqual(addr, b'1K5GjYkZnPFvMDTGaQHTrVnd8wjmrtfR5x')

        ind = [0, 2]
        addr = address_from_xpub(bip32_xpub_from_xprv(bip32_derive(xprv, ind)))
        self.assertEqual(addr, b'1PQYX2uN7NYFd7Hq22ECMzfDcKhtrHmkfi')

        ind = [1, 0]
        addr = address_from_xpub(bip32_xpub_from_xprv(bip32_derive(xprv, ind)))
        self.assertEqual(addr, b'1BvSYpojWoWUeaMLnzbkK55v42DbizCoyq')

        ind = [1, 1]
        addr = address_from_xpub(bip32_xpub_from_xprv(bip32_derive(xprv, ind)))
        self.assertEqual(addr, b'1NXB59hF4QzYpFrB7o6usLBjbk2D3ZqxAL')

        ind = [1, 2]
        addr = address_from_xpub(bip32_xpub_from_xprv(bip32_derive(xprv, ind)))
        self.assertEqual(addr, b'16NLYkKtvYhW1Jp86tbocku3gxWcvitY1w')

        # version/key mismatch in extended parent key
        bmprv = b58decode_check(mprv)
        bad_mprv = b58encode_check(bmprv[0:45] + b'\x01' + bmprv[46:])
        self.assertRaises(ValueError, bip32_ckd, bad_mprv, 1)
        #bip32_ckd(bad_mprv, 1)

        # version/key mismatch in extended parent key
        mpub = bip32_xpub_from_xprv(mprv)
        bmpub = b58decode_check(mpub)
        bad_mpub = b58encode_check(bmpub[0:45] + b'\x00' + bmpub[46:])
        self.assertRaises(ValueError, bip32_ckd, bad_mpub, 1)
        #bip32_ckd(bad_mpub, 1)

        # no private/hardened derivation from pubkey
        self.assertRaises(ValueError, bip32_ckd, mpub, 0x80000000)