Logo

    OCC

    super:Link
    Image
    Tags
    Type
    Post
    Published
    Date
    July 2, 2024
    Featured

    How to harmonize the set-up of key material to operate all three of them as hd-wallets.

    Start with an USB-connected trustanchor to a host computer. Create a mnemonic on the trustanchor and ask for the WIF of the master key. This is necessary as neither bitcoin core nor the Blockstream elementsd client allow import of mnemonic phrases as they don’t directly support BIP-39

    Create a new mnemonic phrase

    Derive the root or master key in different formats

    In elementsd we set-up first a blank wallet

    createwallet 'walletname' false true ""

    Then we import the seed via the WIF encoded masterkey we’ve got from the trustanchor

    sethdseed true cMbNCWdLK3eqENuVUcU6oCcdme4fBgNdUEJAb9sTuuMxPRVdCK65

    Now the hd-wallet inside elementsd (or the same way inside bitcoin core) will transact and sign on top of this key material derived from the newly set seed. to control this we will export the wallet including its Extended Master Private Key.

    dumpwallet 'path/filename'

    Which delivers a wallet dump file of this kind:

    Of relevance is the extended master private key which is the serialization of the core of a hd-wallet object. To deserialize this key we can use the following Python3 code

    Which results is:

    Consequently, we can set up our trustanchor to operate on top of the extended master private key - hd wallet object instead of the seed from the mnemonic phrase.

    This also means that all signing with key material done from within in elementsd on raw transactions can now also be done on the trustanchor acting as a real HSM - hardwrae security module

    But how exactly are elementsd and bitcoin core handling the sethdseed command to get to this result?

    It takes the WIF key: ‘cMbNCWdLK3eqENuVUcU6oCcdme4fBgNdUEJAb9sTuuMxPRVdCK65’ turns it back into the raw private key and calculates it public key by multiplying its raw key with the curve base point.

    > bx wif-to-public --config ./bx.cfg cMbNCWdLK3eqENuVUcU6oCcdme4fBgNdUEJAb9sTuuMxPRVdCK65           
    02aa3dc46791b9f99971551e8162f982867246420f35f3f0a473bc688cd09e2b7f

    The public key becomes than the seed for calculating the new extended master private key. That’s all

    print("Get a Mnemonic")
    msg = OSCMessage('/IHW/bip39Mnemonic', ',is', [0, ""])
    send_osc_message(msg)
    time.sleep(0.2)
    
    > OSCMessage(addrpattern='/IHW/bip39Mnemonic', 
    						 typetags=',iss', 
    						 arguments=(0, '', 'focus nature unfair swap kingdom supply weather piano fine just brief maximum federal nature goat cash crystal rally response joy unique drum merit surprise'))
    msg = OSCMessage('/IHW/bip39MnemonicToPrivateKey', ',ss',["focus nature unfair swap kingdom supply weather piano fine just brief maximum federal nature goat cash crystal rally response joy unique drum merit surprise", ""])
    send_osc_message(msg)
    time.sleep(0.5)
    
    > OSCMessage(addrpattern='/IHW/Bip39MnemonicToPrivateKey', 
    						 typetags=',sss', 
    						 arguments=('005788b752c703494ca821658ae32bf0c93bf07cb7b6ae71b1dbacaa61c5473d05', 
    												'tprv8ZgxMBicQKsPdE9ixNbtp3Qsf4WJUSc6LEf2nh8bgVPrxPQjfbWy83WxWsAF18QXjNepJoJD9iKvjeZ6nBFhEhzWv2TkQsw7NoHm2pGymsm', 
    												'cMbNCWdLK3eqENuVUcU6oCcdme4fBgNdUEJAb9sTuuMxPRVdCK65'))
    # Wallet dump created by Bitcoin v22.1.1
    # * Created on 2023-10-04T16:39:35Z
    # * Best block at time of backup was 1072013 (7d074fd656c27c553b770195b9841e22cfa88eae1abd0ecf7898c3052180322f),
    #   mined on 2023-10-04T16:39:02Z
    
    # extended private masterkey: tprv8ZgxMBicQKsPdWraFbnhmthZQBF472wuTpFzpcKhPBBCBjCYN4kzoScEwCidWctCMwaN7t3W8sBFxuRLYsw2m4VvC4uTProyz62mjScW4dy
    
    # Master private blinding key: d2a32a318d588afcb968fc4a6ca929f4d8b3b3428b36922707964cc528c2d497
    
    cTzM2sYBg9Wztme5N5ENWYSGiquM5HUyRwZvuy3oZP5mhHgCKFhx 2023-10-04T16:39:22Z reserve=1 # addr=tex1qqqga9dzjkedxnwnhkmda42z0ez7u8dwrfx5s6f hdkeypath=m/0'/0'/252'
    ...
    import base58
    import binascii
    
    def deserialize_extended_key(extended_key):
        # Decode the extended key using base58
        decoded = base58.b58decode_check(extended_key)
    
        # Break down the decoded key into its components
        version = decoded[:4]
        depth = decoded[4:5]
        parent_fingerprint = decoded[5:9]
        child_number = decoded[9:13]
        chain_code = decoded[13:45]
        key_data = decoded[45:]
    
        # Convert to hexadecimal for easier readability
        return {
            "version": binascii.hexlify(version).decode(),
            "depth": binascii.hexlify(depth).decode(),
            "parent_fingerprint": binascii.hexlify(parent_fingerprint).decode(),
            "child_number": binascii.hexlify(child_number).decode(),
            "chain_code": binascii.hexlify(chain_code).decode(),
            "key_data": binascii.hexlify(key_data).decode()
        }
    
    # Extended master key
    extended_key = "tprv8ZgxMBicQKsPdWraFbnhmthZQBF472wuTpFzpcKhPBBCBjCYN4kzoScEwCidWctCMwaN7t3W8sBFxuRLYsw2m4VvC4uTProyz62mjScW4dy"
    
    # Deserialize and print the components
    components = deserialize_extended_key(extended_key)
    print(components)
    python3 '/Users/thomasfuerstner/Downloads/test/occExtendedMasterKey.py'
    {'version': '04358394', 'depth': '00', 'parent_fingerprint': '00000000', 'child_number': '00000000', 'chain_code': '4088adb8ebf8ed953ba7bc16e3982460b64fabd896eddd821ff0e4bf4b01ad04', 'key_data': '00b9aab579aa1dc5f73e59450fb7b817b7e7ca583a03e98297296cb49d414d415f'}