.. | ||
bip85_test.go | ||
bip85.go | ||
bip-0085.mediawiki | ||
README.md |
BIP85 - Deterministic Entropy From BIP32 Keychains
This package implements BIP85, which allows for deterministic derivation of entropy from a BIP32 master key. This enables a single seed to generate multiple wallet keys, mnemonics, and random values in a fully deterministic way.
Overview
BIP85 enables a variety of use cases:
- Generate multiple BIP39 mnemonic seeds from a single master key
- Derive Bitcoin HD wallet seeds (WIF format)
- Create extended private keys (XPRV)
- Generate deterministic random values for dice rolls, hex values, and passwords
Usage Examples
Initialization
import (
"fmt"
"git.eeqj.de/sneak/secret/internal/bip85"
"github.com/btcsuite/btcd/btcutil/hdkeychain"
)
// Parse an existing master key
masterKeyStr := "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb"
masterKey, err := bip85.ParseMasterKey(masterKeyStr)
if err != nil {
panic(err)
}
Derive BIP39 Mnemonic
// Parameters:
// - language (0 = English, 1 = Japanese, 2 = Korean, 3 = Spanish, etc.)
// - number of words (12, 15, 18, 21, or 24)
// - index (allows multiple seeds of the same type)
entropy, err := bip85.DeriveBIP39Entropy(masterKey, 0, 12, 0)
if err != nil {
panic(err)
}
// Use the entropy with github.com/tyler-smith/go-bip39
// to generate a mnemonic
mnemonic, err := bip39.NewMnemonic(entropy)
if err != nil {
panic(err)
}
fmt.Println("12-word BIP39 mnemonic:", mnemonic)
Derive HD-WIF Key
// Create a WIF format key for Bitcoin Core's hdseed
wif, err := bip85.DeriveWIFKey(masterKey, 0)
if err != nil {
panic(err)
}
fmt.Println("WIF Key:", wif)
Derive XPRV
// Create an extended private key (XPRV)
xprv, err := bip85.DeriveXPRV(masterKey, 0)
if err != nil {
panic(err)
}
fmt.Println("XPRV:", xprv.String())
Generate Hex Data
// Generate arbitrary hex data (16-64 bytes)
hex, err := bip85.DeriveHex(masterKey, 32, 0)
if err != nil {
panic(err)
}
fmt.Println("32 bytes of hex:", hex)
Dice Rolls
// Generate dice rolls
// sides: number of sides on the die
// rolls: number of rolls to generate
// index: allows multiple sets of the same type
rolls, err := bip85.DeriveDiceRolls(masterKey, 6, 10, 0)
if err != nil {
panic(err)
}
fmt.Print("10 rolls of a 6-sided die: ")
for _, roll := range rolls {
fmt.Print(roll, " ")
}
fmt.Println()
DRNG (Deterministic Random Number Generator)
// First derive entropy
path := "m/83696968'/0'/0'"
entropy, err := bip85.DeriveBIP85Entropy(masterKey, path)
if err != nil {
panic(err)
}
// Create a deterministic random number generator
drng := bip85.NewBIP85DRNG(entropy)
// Read arbitrary amount of random bytes
buffer := make([]byte, 32)
_, err = drng.Read(buffer)
if err != nil {
panic(err)
}
fmt.Printf("Random bytes: %x\n", buffer)
BIP85 Paths
The derivation paths follow the format:
m/83696968'/{app}'/{parameters}
Where:
83696968'
is the BIP85 root path (BIP in ASCII){app}'
is the application number:39'
for BIP39 mnemonics2'
for HD-WIF keys32'
for XPRV128169'
for HEX data707764'
for Base64 passwords707785'
for Base85 passwords89101'
for dice rolls828365'
for RSA keys
{parameters}
are application-specific parameters
Test Vectors
This implementation passes all the test vectors from the BIP85 specification:
- Basic test cases
- BIP39 12, 18, and 24 word mnemonics
- HD-WIF keys
- XPRV
- SHAKE256 DRNG output
- Dice rolls
Run the tests with verbose output to see the test vectors and results:
go test -v git.eeqj.de/sneak/secret/internal/bip85