HD Key Generation · bitcoin-s
In modern Bitcoin wallets, users only need to write down
a sequence of words, and that sequence is a complete backup
of their wallet. This is thanks to what’s called Hierarchical
Deterministic key generation. In short, every wallet using HD
key generation has a root seed for each wallet, and this
seed can be used to generate an arbitrary amount of later
private and public keys. This is done in a standardized manner,
so different wallets can operate with the same standard.
If you want to jump into the details of how this work,
you should check out
BIP 32.
Bitcoin-S supports generating keys in this fashion. Here’s a
full example of how to obtain a wallet seed, and then
use that to generate further private and public keys:
import
scodec.bits._
import
org.bitcoins.core.crypto._
import
org.bitcoins.core.hd._
val
entropy: BitVector
= MnemonicCode
.getEntropy256Bits
val
mnemonicCode = MnemonicCode
.fromEntropy(entropy)
mnemonicCode.words
val
bip39Seed = BIP39Seed
.fromMnemonic(mnemonicCode,
password = "secret password"
)
val
xpriv = ExtPrivateKey
.fromBIP39Seed(ExtKeyVersion
.SegWitMainNetPriv
,
bip39Seed)
val
xpub = xpriv.extPublicKey
val
segwitPath = SegWitHDPath
.fromString("m/84'/0'/0'/0/0"
)
val
otherSegwitPath =
SegWitHDPath
(HDCoinType
.Bitcoin
,
accountIndex = 0
,
HDChainType
.External
,
addressIndex = 0
)
segwitPath == otherSegwitPath
Mục lục bài viết
Generating new addresses without having access to the private key
One the coolest features of HD wallets is that it’s possible
to generate addresses offline, without having access to the
private keys. This feature is commonly called watch-only
wallets, where a wallet can import information about all
your past and future transactions, without being able to
spend or steal any of your money.
Let’s see an example of this:
import
scala.util.Success
import
org.bitcoins.core.protocol.script._
import
org.bitcoins.core.protocol.Bech32Address
import
org.bitcoins.core.config.TestNet3
val
accountPath = BIP32Path
.fromString("m/84'/0'/0'"
)
val
accountXpub = {
val
accountXpriv = xpriv.deriveChildPrivKey(accountPath)
accountXpriv.extPublicKey
}
val
firstAddressPath = SegWitHDPath
.fromString("m/84'/0'/0'/0/0"
)
val
firstAccountAddress = {
val
Some
(pathDiff) = accountPath.diff(firstAddressPath)
val
Success
(extPubKey) = accountXpub.deriveChildPubKey(pathDiff)
val
pubkey = extPubKey.key
val
scriptPubKey = P2WPKHWitnessSPKV0
(pubkey)
Bech32Address
(scriptPubKey, TestNet3
)
}
firstAccountAddress.value
val
nextAddressPath: SegWitHDPath
= firstAddressPath.next
Signing things with HD keys
Please see sign.md for information on how to sign things with HD keys.