# BIP85 - Deterministic Entropy From BIP32 Keychains This package implements [BIP85](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki), 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 ```go 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 ```go // 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 ```go // 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 ```go // 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 ```go // 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 ```go // 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) ```go // 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 mnemonics - `2'` for HD-WIF keys - `32'` for XPRV - `128169'` for HEX data - `707764'` for Base64 passwords - `707785'` for Base85 passwords - `89101'` for dice rolls - `828365'` 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 ``` ## References - [BIP85 Specification](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki) - [Bitcoin Core](https://github.com/bitcoin/bitcoin) - [BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) - [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki)