--- id: key-manager title: Key Manager --- ### Key Manager The key manager module's goal is to encapusulate all private key interactions with the [wallet](../applications/wallet.md) project. As of this writing, there is only one type of `KeyManager` - [`BIP39KeyManager`](../../key-manager/src/main/scala/org/bitcoins/keymanager/bip39/BIP39KeyManager.scala). The [`BIP39KeyManager`](../../key-manager/src/main/scala/org/bitcoins/keymanager/bip39/BIP39KeyManager.scala) stores a [`MnemonicCode`](../../core/src/main/scala/org/bitcoins/core/crypto/MnemonicCode.scala) on disk which can be decrypted and used as a hot wallet. Over the long run, we want to make it so that the wallet project needs to communicate with the key-manager to access private keys. This means that ALL SIGNING should be done inside of the key-manager, and private keys should not leave the key manager. This makes it easier to reason about the security characteristics of our private keys, and a way to provide a uniform interface for alternative key storage systems (hsm, cloud based key storage, etc) to be plugged into the bitcoin-s library. #### Creating a key manager The first thing you need create a key manager is some entropy. A popular way for bitcoin wallet's to represent entropy is [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) which you [can use in bitcoin-s](../../core/src/main/scala/org/bitcoins/core/crypto/BIP39Seed.scala) You can generate a `MnemonicCode` in bitcoin-s with the following code ```scala mdoc import org.bitcoins.core.crypto._ //get 256 bits of random entropy val entropy = MnemonicCode.getEntropy256Bits val mnemonic = MnemonicCode.fromEntropy(entropy) //you can print that mnemonic seed with this println(mnemonic.words) ``` Now that we have a `MnemonicCode` that was securely generated, we need to now create `KeyManagerParams` which tells us how to generate generate specific kinds of addresses for wallets. `KeyManagerParams` takes 3 parameters: 1. `seedPath` there is where we store the `MnemonicCode` on your file system 2. [`purpose`](../../core/src/main/scala/org/bitcoins/core/hd/HDPurpose.scala) which represents what type of utxo this `KeyManager` is associated with. The specification for this is in [BIP43](https://github.com/bitcoin/bips/blob/master/bip-0043.mediawiki) 3. [`network`](../../core/src/main/scala/org/bitcoins/core/config/NetworkParameters.scala) what cryptocurrency network this key manager is associated with This controls how the root key is defined. The combination of `purpose` and `network` determine how the root `ExtKey` is serialized. For more information on how this works please see [hd-keys](hd-keys.md) Now we can construct a native segwit key manager for the regtest network! ```scala mdoc import org.bitcoins.core.crypto._ import org.bitcoins.core.config._ import org.bitcoins.core.hd._ import org.bitcoins.keymanager._ import org.bitcoins.keymanager.bip39._ import java.nio.file._ //this will create a temp directory with the prefix 'key-manager-example` that will //have a file in it called "encrypted-bitcoin-s-seed.json" val seedPath = Files.createTempDirectory("key-manager-example").resolve(WalletStorage.ENCRYPTED_SEED_FILE_NAME) //let's create a native segwit key manager val purpose = HDPurposes.SegWit //let's choose regtest as our network val network = RegTest val kmParams = KeyManagerParams(seedPath, purpose, network) val km = BIP39KeyManager.initializeWithMnemonic(mnemonic, kmParams) val rootXPub = km.right.get.getRootXPub println(rootXPub) ``` Which should print something that looks like this `vpub5SLqN2bLY4WeXxMqwJHJFBEwxSscGB2uDUnsTS3edVjZEwTrQDFDNqoR2xLqARQPabGaXsHSTenTRcqm2EnB9MpuC4vSk3LqSgNmGGZtuq7` which is a native segwit `ExtPubKey` for the regtest network! You can always change the `network` or `purpose` to support different things. You do _not_ need to initialize the key manager again after initializing it once. You can use the same `mnemonic` for different networks, which you control `KeyManagerParams`. ```scala //let's create a nested segwit key manager for mainnet val mainnetKmParams = KeyManagerParams(seedPath, HDPurposes.SegWit, MainNet) //we do not need to all `initializeWithMnemonic()` again as we have saved the seed to dis val mainnetKeyManager = KeyManager(mnemonic, mainnetKmParams) val mainnetXpub = mainnetKeyManager.getRootXPub println(mainnetXpub) ``` Which gives us something that looks like this `zpub6jftahH18ngZw98KGjRo5XcxeKTQ2eztsvskb1dC9XF5TLimQquTs6Ry7nBBA425D9joXmfgJJCexmJ1u2SELJZJfRi95gcnXadLpZzYb5c` which is a p2sh wrapped segwit `ExtPubKey` for the bitcoin main network! #### Creating a key manager from existing mnemonic To create a `KeyManager` from existing mnemonic you need to specify the `seedPath` and then construct the `KeyManagerParams` that you would like. Finally you call `KeyManager.fromParams()` that reads the mnemonic from disk and create's the key manager