secret/internal/bip85/README.md
2025-05-28 04:02:55 -07:00

169 lines
4.0 KiB
Markdown

# 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)