Documentation
¶
Overview ¶
Package bip85 implements BIP85 (Deterministic Entropy From BIP32 Keychains), version 2.0.0 of the specification.
BIP85 derives deterministic entropy from a BIP32 master key using HMAC-SHA512. A single master backup recovers all derived material: mnemonics, private keys, passwords, symmetric keys, and dice rolls. The derivation is one-way and hardened - knowledge of any derived output reveals nothing about the master key or other derived outputs.
Basic usage (BIP32 master key to BIP39 mnemonic):
key, _ := bip85.ParseKey("xprv9s21ZrQH143K...")
defer key.Zero()
path := bip85.BIP39Path(bip85.LangEnglish, 12, 0)
entropy, _ := bip85.DeriveEntropy(key, path)
defer bip85.ZeroBytes(entropy)
mnemonic, _ := bip85.DeriveBIP39(entropy, bip85.LangEnglish, 12)
Derivation Pipeline ¶
The BIP85 derivation pipeline has three stages:
- Key derivation: BIP32 hardened child derivation to a leaf key, or custom derivation via WithCustomDeriver, or direct key input via EntropyFromRawKey.
- Entropy extraction: HMAC-SHA512(key="bip-entropy-from-k", msg=leafKey) produces 64 bytes of deterministic entropy.
- Application: the 64-byte entropy is transformed into the target format (mnemonic, WIF, XPRV, hex, password, dice rolls, or unlimited DRNG stream).
Applications ¶
The following BIP85 applications are supported:
- BIP39: Mnemonic derivation via DeriveBIP39 (10 languages, 12-24 words)
- WIF: Compressed private key via DeriveWIF (secp256k1, network-aware)
- XPRV: Extended private key via DeriveXPRV (reversed field order per spec)
- HEX: Raw hex entropy via DeriveHex (16-64 bytes)
- BASE64: Password via DeriveBase64 (20-86 characters, RFC 4648)
- BASE85: Password via DeriveBase85 (10-80 characters, RFC 1924)
- DICE: Dice rolls via DeriveDice (rejection sampling, 2 to 2^32-1 sides)
- DRNG: Unlimited byte stream via NewDRNG (SHAKE256 XOF, io.Reader)
RSA key generation is not provided because Go 1.24+ mixes system entropy into crypto/rsa for FIPS 140-3, making output non-deterministic. Use the DRNG directly with a deterministic RSA implementation. See RSAPath and GPGCreationTimestamp.
Two-Tier API ¶
The library provides two entry points for entropy derivation:
BIP32-native (Bitcoin and compatible chains):
entropy, err := bip85.DeriveEntropy(parsedKey, path)
Chain-agnostic (Solana, Cardano, Polkadot, or any key bytes):
entropy, err := bip85.EntropyFromRawKey(myDerivedKeyBytes)
Application functions (DeriveBIP39, DeriveHex, DeriveWIF, DeriveXPRV, DeriveBase64, DeriveBase85, DeriveDice) accept raw entropy bytes and are independent of the derivation method. Network parameters for WIF and XPRV are configurable via chaincfg.Params; pass nil for Bitcoin mainnet.
Concurrency ¶
ParseKey returns an *hdkeychain.ExtendedKey that is safe for concurrent use from multiple goroutines. Each derivation allocates fresh child keys internally. DeriveEntropy, DeriveKeyAndEntropy, and EntropyFromRawKey are safe for concurrent use with the same parsed key.
DRNG instances are NOT safe for concurrent use. Each goroutine must create its own instance via NewDRNG.
Security ¶
All returned byte slices (entropy, derived keys) are fresh allocations owned by the caller. Call ZeroBytes on them when no longer needed. Internally, all intermediate key material is zeroed via defer. The Go garbage collector may copy data before zeroing occurs; for hardware-grade security, use a hardware wallet.
All functions that return secret strings (DeriveBIP39, DeriveWIF, DeriveXPRV, DeriveHex, DeriveBase64, DeriveBase85) document the output as secret material. Do not log, trace, or serialize these values. *hdkeychain.ExtendedKey.String() outputs the full xprv in base58 - do not pass parsed keys to loggers or fmt.Print.
All derived outputs are only as secure as the master key. A weak or compromised master key compromises all derived entropy.
Specification ¶
BIP85: https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki
Example ¶
// Parse a BIP32 master private key.
key, err := bip85.ParseKey("xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb")
if err != nil {
log.Fatal(err)
}
defer key.Zero()
// Derive 64 bytes of entropy at path m/83696968'/0'/0'.
path, err := bip85.ParsePath("m/83696968'/0'/0'")
if err != nil {
log.Fatal(err)
}
entropy, err := bip85.DeriveEntropy(key, path)
if err != nil {
log.Fatal(err)
}
defer bip85.ZeroBytes(entropy)
fmt.Println(hex.EncodeToString(entropy[:8]) + "...")
Output: efecfbccffea3132...
Index ¶
- Constants
- Variables
- func DecodeWIF(wif string, net *chaincfg.Params) (key []byte, compressed bool, err error)
- func DeriveBIP39(entropy []byte, language uint32, words int) (string, error)
- func DeriveBase64(entropy []byte, pwdLen int) (string, error)
- func DeriveBase85(entropy []byte, pwdLen int) (string, error)
- func DeriveDice(entropy []byte, sides uint32, rolls int) (values []int, formatted string, err error)
- func DeriveEntropy(key *hdkeychain.ExtendedKey, path Path, opts ...Option) ([]byte, error)
- func DeriveEntropyFromString(xprv string, path Path, opts ...Option) ([]byte, error)
- func DeriveHex(entropy []byte, numBytes int) (string, error)
- func DeriveKeyAndEntropy(key *hdkeychain.ExtendedKey, path Path, opts ...Option) (derivedKey, entropy []byte, err error)
- func DeriveRolls(entropy []byte, sides uint32, rolls int) ([]int, error)
- func DeriveWIF(entropy []byte, net *chaincfg.Params) (string, error)
- func DeriveXPRV(entropy []byte, net *chaincfg.Params) (string, error)
- func EntropyFromRawKey(privateKey []byte, opts ...Option) ([]byte, error)
- func FormatRolls(rollValues []int, sides uint32) string
- func ParseKey(xprv string) (*hdkeychain.ExtendedKey, error)
- func ValidateSecp256k1Key(key []byte) error
- func ZeroBytes(buf []byte)
- type DRNG
- type Option
- type Path
- func BIP39Path(language, words, index uint32) Path
- func Base64Path(pwdLen, index uint32) Path
- func Base85Path(pwdLen, index uint32) Path
- func CorePath(appCode, index uint32) Path
- func DicePath(sides, rolls, index uint32) Path
- func HexPath(numBytes, index uint32) Path
- func ParsePath(s string) (Path, error)
- func RSAPath(keyBits, keyIndex uint32) Path
- func WIFPath(index uint32) Path
- func XPRVPath(index uint32) Path
Examples ¶
Constants ¶
const ( // Base64MinLen is the minimum password length for the BASE64 application. Base64MinLen = 20 // Base64MaxLen is the maximum password length for the BASE64 application. Base64MaxLen = 86 )
const ( // Base85MinLen is the minimum password length for the BASE85 application. Base85MinLen = 10 // Base85MaxLen is the maximum password length for the BASE85 application. Base85MaxLen = 80 )
const ( LangEnglish uint32 = 0 LangJapanese uint32 = 1 LangKorean uint32 = 2 LangSpanish uint32 = 3 LangChineseSimplified uint32 = 4 LangChineseTraditional uint32 = 5 LangFrench uint32 = 6 LangItalian uint32 = 7 LangCzech uint32 = 8 LangPortuguese uint32 = 9 )
BIP39 language codes as defined in the BIP85 spec.
const ( // DiceMinSides is the minimum number of sides for the DICE application. DiceMinSides = 2 // DiceMaxSides is the maximum number of sides for the DICE application (2^32 - 1). DiceMaxSides uint32 = 1<<32 - 1 )
const ( // HexMinBytes is the minimum byte count for the HEX application (16). HexMinBytes = 16 // HexMaxBytes is the maximum byte count for the HEX application (64). HexMaxBytes = 64 )
const ( AppBIP39 uint32 = 39 // BIP39 mnemonic derivation AppWIF uint32 = 2 // HD-Seed WIF (compressed private key) AppXPRV uint32 = 32 // BIP32 extended private key AppHex uint32 = 128169 // Raw hex entropy (16-64 bytes) AppBase64 uint32 = 707764 // Base64-encoded password (20-86 chars) AppBase85 uint32 = 707785 // RFC 1924 Base85-encoded password (10-80 chars) AppRSA uint32 = 828365 // RSA key generation via DRNG AppDice uint32 = 89101 // Dice roll generation via rejection sampling )
BIP85 application codes as defined in the specification. These are used as the second hardened component in derivation paths.
const ( // RSAMinBits is the minimum RSA key size for the RSA application (1024). RSAMinBits = 1024 // RSAMaxBits is the maximum RSA key size for the RSA application (16384). RSAMaxBits = 16384 // GPGCreationTimestamp is the UNIX epoch timestamp that MUST be used as // the creation date for GPG keys derived from BIP85 RSA output. This is // the Bitcoin genesis block timestamp (2009-01-03 18:15:05 UTC). // // BIP85 spec: "the creation date MUST be fixed to UNIX Epoch timestamp // 1231006505 [...] because the key fingerprint is affected by the // creation date." // // This library does not generate GPG or RSA keys directly. Consumers // building GPG keys from BIP85 RSA output via the DRNG must use this // constant as the key creation timestamp. GPGCreationTimestamp int64 = 1231006505 )
Variables ¶
var ( // ErrInvalidPath indicates a malformed or non-BIP85 derivation path. ErrInvalidPath = errors.New("bip85: invalid derivation path") // ErrIncompletePath indicates a path with too few segments for the // target application. ErrIncompletePath = errors.New("bip85: incomplete derivation path") // ErrNonHardenedComponent indicates a path component that is not hardened. // BIP85 requires ALL path components to be hardened. ErrNonHardenedComponent = errors.New("bip85: all path components must be hardened") // ErrPublicKeyNotAllowed indicates the caller passed a public extended key // (xpub/tpub). BIP85 requires a private extended key (xprv/tprv). ErrPublicKeyNotAllowed = errors.New("bip85: private extended key required, got public key") // ErrInvalidKey indicates the extended key string could not be parsed. ErrInvalidKey = errors.New("bip85: invalid extended key") // ErrInvalidKeyRange indicates a derived private key is zero or exceeds // the secp256k1 curve order. The caller should try the next index. ErrInvalidKeyRange = errors.New("bip85: derived key out of valid range, try next index") // ErrNilKey indicates a nil key was passed to a function. ErrNilKey = errors.New("bip85: nil key") // ErrEmptyKeyMaterial indicates nil or empty key material was provided, // either from a custom deriver or directly to EntropyFromRawKey. ErrEmptyKeyMaterial = errors.New("bip85: empty key material") // ErrInvalidHMACKey indicates the custom HMAC key option is nil or empty. ErrInvalidHMACKey = errors.New("bip85: HMAC key must not be nil or empty") // ErrPostProcessorShort indicates a post-processor returned fewer than // 64 bytes, which is insufficient for BIP85 applications. ErrPostProcessorShort = errors.New("bip85: post-processor must return at least 64 bytes") // ErrInvalidLength indicates a length parameter is out of the allowed // range for the target application. ErrInvalidLength = errors.New("bip85: invalid length parameter") // ErrCorruptedWordlist indicates an embedded BIP39 wordlist failed // SHA256 integrity verification. This likely indicates a tampered binary. ErrCorruptedWordlist = errors.New("bip85: corrupted BIP39 wordlist (SHA256 mismatch)") // ErrInvalidWordCount indicates the requested word count is not valid // for BIP39. Valid counts: 12, 15, 18, 21, 24. ErrInvalidWordCount = errors.New("bip85: invalid word count") // ErrInvalidLanguage indicates an unsupported BIP39 language code. // Valid codes: 0 (English) through 9 (Portuguese). ErrInvalidLanguage = errors.New("bip85: invalid language code") // ErrInvalidDiceSides indicates the sides parameter is out of the // allowed range for the DICE application. Valid: 2 to 2^32-1. ErrInvalidDiceSides = errors.New("bip85: invalid dice sides") // ErrInvalidDiceRolls indicates the rolls parameter is less than 1. ErrInvalidDiceRolls = errors.New("bip85: invalid dice rolls") )
Sentinel errors returned by the BIP85 derivation pipeline. Callers can use errors.Is to match these. Grouped by subsystem.
Functions ¶
func DecodeWIF ¶
DecodeWIF decodes a WIF string and returns the 32-byte raw private key and whether it was compressed. The returned key is a fresh allocation; call ZeroBytes on it when done.
If net is non-nil, the WIF is verified to match the given network. If net is nil, the network check is skipped.
func DeriveBIP39 ¶
DeriveBIP39 derives a BIP39 mnemonic from BIP85 entropy.
The returned mnemonic is a secret recovery phrase. Do not log it, display it in UI without user intent, or pass it to tracing frameworks.
The entropy is truncated to the byte length required for the given word count, then a SHA256 checksum is appended per BIP39. The combined bits are split into 11-bit groups (MSB-first), each group indexing into the wordlist for the given language.
Valid word counts: 12, 15, 18, 21, 24. Language codes: 0=English through 9=Portuguese.
Japanese mnemonics use the ideographic space (U+3000) as separator per the BIP39 specification. All other languages use ASCII space.
The output words use the same Unicode normalization form as the embedded BIP39 wordlists (NFKD, per BIP39 spec). Other implementations may output NFC-normalized text. Both forms represent the same words and produce the same BIP39 seed when processed through PBKDF2.
Path: m/83696968'/39'/{language}'/{words}'/{index}'.
Example ¶
key, err := bip85.ParseKey("xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb")
if err != nil {
log.Fatal(err)
}
defer key.Zero()
path := bip85.BIP39Path(bip85.LangEnglish, 12, 0)
entropy, err := bip85.DeriveEntropy(key, path)
if err != nil {
log.Fatal(err)
}
defer bip85.ZeroBytes(entropy)
mnemonic, err := bip85.DeriveBIP39(entropy, bip85.LangEnglish, 12)
if err != nil {
log.Fatal(err)
}
fmt.Println(mnemonic)
fmt.Println(strings.Count(mnemonic, " ")+1, "words")
Output: girl mad pet galaxy egg matter matrix prison refuse sense ordinary nose 12 words
func DeriveBase64 ¶
DeriveBase64 derives a Base64-encoded password from BIP85 entropy. pwdLen (20-86) controls the length of the output password string.
The returned string is a secret password derived from key material. Do not log it or pass it to tracing frameworks.
All 64 bytes of entropy are Base64-encoded using standard RFC 4648 encoding (NOT URL-safe), then the result is truncated to pwdLen characters. Passwords up to 86 characters never contain padding because 64 bytes encode to 86 data characters plus 2 padding characters (88 total), and the maximum pwdLen of 86 stops before any padding.
Path: m/83696968'/707764'/{pwdLen}'/{index}'.
func DeriveBase85 ¶
DeriveBase85 derives an RFC 1924 Base85-encoded password from BIP85 entropy. pwdLen (10-80) controls the length of the output password string.
The returned string is a secret password derived from key material. Do not log it or pass it to tracing frameworks.
All 64 bytes of entropy are encoded using the RFC 1924 Base85 alphabet (NOT Adobe Ascii85, NOT Go's encoding/ascii85), then the result is truncated to pwdLen characters. 64 bytes -> 80 Base85 characters, so the maximum pwd_len of 80 uses the full encoding.
Path: m/83696968'/707785'/{pwdLen}'/{index}'.
func DeriveDice ¶
func DeriveDice(entropy []byte, sides uint32, rolls int) (values []int, formatted string, err error)
DeriveDice derives formatted dice rolls from BIP85 entropy. This is a convenience function that calls DeriveRolls and FormatRolls.
Returns both the raw roll values and the formatted string.
Example ¶
key, err := bip85.ParseKey("xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb")
if err != nil {
log.Fatal(err)
}
defer key.Zero()
// Roll a 6-sided die 10 times at index 0.
path := bip85.DicePath(6, 10, 0)
entropy, err := bip85.DeriveEntropy(key, path)
if err != nil {
log.Fatal(err)
}
defer bip85.ZeroBytes(entropy)
values, formatted, err := bip85.DeriveDice(entropy, 6, 10)
if err != nil {
log.Fatal(err)
}
fmt.Println(formatted)
fmt.Println(len(values), "rolls")
Output: 1,0,0,2,0,1,5,5,2,4 10 rolls
func DeriveEntropy ¶
func DeriveEntropy(key *hdkeychain.ExtendedKey, path Path, opts ...Option) ([]byte, error)
DeriveEntropy derives BIP85 entropy from the given pre-parsed master key and derivation path. It returns the 64-byte HMAC-SHA512 output.
The returned entropy slice is a fresh allocation owned by the caller. Call ZeroBytes on it when done to clear secret material.
For batch derivation, parse the key once with ParseKey and reuse it across multiple calls.
func DeriveEntropyFromString ¶
DeriveEntropyFromString is a convenience wrapper that parses the xprv string and calls DeriveEntropy. The parsed key is zeroed automatically on return. For batch derivation, prefer ParseKey + DeriveEntropy to avoid repeated parsing.
Example ¶
xprv := "xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb"
path, _ := bip85.ParsePath("m/83696968'/0'/0'")
entropy, err := bip85.DeriveEntropyFromString(xprv, path)
if err != nil {
log.Fatal(err)
}
defer bip85.ZeroBytes(entropy)
fmt.Println(len(entropy), "bytes")
Output: 64 bytes
func DeriveHex ¶
DeriveHex derives a hex-encoded entropy string from BIP85 entropy. numBytes (16-64) controls how many bytes are kept from the entropy before hex encoding. Per the spec, "truncate trailing (least significant) bytes" means keeping the first numBytes.
The returned string is secret material (raw key entropy in hex form). Do not log it, include it in error messages, or pass it to tracing frameworks. Go strings cannot be zeroed after use.
The entropy slice must be at least numBytes long.
Path: m/83696968'/128169'/{numBytes}'/{index}'.
Example ¶
key, err := bip85.ParseKey("xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb")
if err != nil {
log.Fatal(err)
}
defer key.Zero()
path := bip85.HexPath(32, 0)
entropy, err := bip85.DeriveEntropy(key, path)
if err != nil {
log.Fatal(err)
}
defer bip85.ZeroBytes(entropy)
hexStr, err := bip85.DeriveHex(entropy, 32)
if err != nil {
log.Fatal(err)
}
fmt.Println(hexStr)
fmt.Println(len(hexStr)/2, "bytes")
Output: ea3ceb0b02ee8e587779c63f4b7b3a21e950a213f1ec53cab608d13e8796e6dc 32 bytes
func DeriveKeyAndEntropy ¶
func DeriveKeyAndEntropy(key *hdkeychain.ExtendedKey, path Path, opts ...Option) (derivedKey, entropy []byte, err error)
DeriveKeyAndEntropy derives both the BIP85 intermediate key and entropy.
The derivedKey is the 32-byte private key at the final path depth (the "k" in the BIP85 spec). The entropy is the 64-byte HMAC-SHA512 output. Both are secret material - call ZeroBytes on each when no longer needed.
func DeriveRolls ¶
DeriveRolls derives a DICE application result from BIP85 entropy.
Roll values are zero-indexed: an N-sided die produces values in [0, N-1]. The DRNG is seeded with the 64-byte entropy, then rejection sampling produces each roll by reading the minimum number of bytes, retaining the most significant bits, and discarding values >= sides.
sides must be in [2, 2^32-1]. rolls must be in [1, 2^32-1].
Path: m/83696968'/89101'/{sides}'/{rolls}'/{index}'.
func DeriveWIF ¶
DeriveWIF derives a compressed WIF-encoded private key from BIP85 entropy. The first 32 bytes of entropy are used as the private key.
The returned string is a secret private key. Do not log it or pass it to tracing frameworks.
The net parameter controls the version byte in the WIF encoding. Pass &chaincfg.MainNetParams for Bitcoin mainnet (prefix K/L), &chaincfg.TestNet3Params for testnet (prefix c), or custom chaincfg.Params for other BIP32-compatible chains. If nil, defaults to Bitcoin mainnet.
The key is validated against the secp256k1 curve order. If invalid (probability < 1 in 2^127), ErrInvalidKeyRange is returned and the caller should try the next index.
Example ¶
key, err := bip85.ParseKey("xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb")
if err != nil {
log.Fatal(err)
}
defer key.Zero()
path := bip85.WIFPath(0)
entropy, err := bip85.DeriveEntropy(key, path)
if err != nil {
log.Fatal(err)
}
defer bip85.ZeroBytes(entropy)
wif, err := bip85.DeriveWIF(entropy, nil) // nil = Bitcoin mainnet
if err != nil {
log.Fatal(err)
}
fmt.Println(wif)
Output: Kzyv4uF39d4Jrw2W7UryTHwZr1zQVNk4dAFyqE6BuMrMh1Za7uhp
func DeriveXPRV ¶
DeriveXPRV derives a BIP32 extended private key from the given 64-byte BIP85 entropy.
The returned string is a secret extended private key. Do not log it or pass it to tracing frameworks.
The net parameter controls the version bytes in the serialized key. Pass &chaincfg.MainNetParams for Bitcoin mainnet (xprv prefix), &chaincfg.TestNet3Params for testnet (tprv prefix), or custom chaincfg.Params for other BIP32-compatible chains. If nil, defaults to Bitcoin mainnet.
Per the BIP85 spec, the field ordering is REVERSED from BIP32 convention:
- First 32 bytes of entropy = chain code
- Second 32 bytes of entropy = private key
The private key is validated against the secp256k1 curve order. If invalid, ErrInvalidKeyRange is returned and the caller should try the next index.
Depth, parent fingerprint, and child number are forced to zero per spec.
Example ¶
key, err := bip85.ParseKey("xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb")
if err != nil {
log.Fatal(err)
}
defer key.Zero()
path := bip85.XPRVPath(0)
entropy, err := bip85.DeriveEntropy(key, path)
if err != nil {
log.Fatal(err)
}
defer bip85.ZeroBytes(entropy)
xprv, err := bip85.DeriveXPRV(entropy, nil) // nil = Bitcoin mainnet
if err != nil {
log.Fatal(err)
}
fmt.Println(xprv)
Output: xprv9s21ZrQH143K2srSbCSg4m4kLvPMzcWydgmKEnMmoZUurYuBuYG46c6P71UGXMzmriLzCCBvKQWBUv3vPB3m1SATMhp3uEjXHJ42jFg7myX
func EntropyFromRawKey ¶
EntropyFromRawKey applies the BIP85 HMAC-SHA512 entropy extraction to a raw private key of any length. This is the chain-agnostic foundation of BIP85: HMAC-SHA512(key="bip-entropy-from-k", msg=privateKey) -> 64 bytes.
Use this when you have your own key derivation (SLIP-10, Ed25519, Sr25519, or any non-BIP32 scheme) and want to apply the BIP85 entropy extraction step. The privateKey can be any length - the HMAC accepts arbitrary input.
For standard BIP32 derivation, use DeriveEntropy instead.
The caller is responsible for zeroing the input privateKey after use. The returned entropy is a fresh allocation owned by the caller.
Example ¶
// Chain-agnostic: apply BIP85 HMAC extraction to any raw private key.
// No BIP32 types needed. Works with Ed25519, Sr25519, or any key bytes.
rawKey, _ := hex.DecodeString("cca20ccb0e9a90feb0912870c3323b24874b0ca3d8018c4b96d0b97c0e82ded0")
defer bip85.ZeroBytes(rawKey)
entropy, err := bip85.EntropyFromRawKey(rawKey)
if err != nil {
log.Fatal(err)
}
defer bip85.ZeroBytes(entropy)
fmt.Println(len(entropy), "bytes")
fmt.Println(hex.EncodeToString(entropy[:8]) + "...")
Output: 64 bytes efecfbccffea3132...
func FormatRolls ¶
FormatRolls formats dice roll values as a comma-separated string. Values are zero-padded to the width of (sides-1) for readability when sides >= 10.
func ParseKey ¶
func ParseKey(xprv string) (*hdkeychain.ExtendedKey, error)
ParseKey parses a base58check-encoded extended private key (xprv/tprv). Whitespace is trimmed automatically. Public keys are rejected.
The returned key can be reused across multiple derivations without re-parsing. It is safe for concurrent use from multiple goroutines since derivation creates new child keys at each level.
Security: the returned ExtendedKey's String() method outputs the full xprv in base58. Do not pass the key to loggers, fmt.Print, or any framework that auto-serializes function arguments.
func ValidateSecp256k1Key ¶
ValidateSecp256k1Key checks whether a 32-byte value is a valid secp256k1 private key (non-zero and less than the curve order). Returns nil if valid.
BIP85 applications that use raw entropy as an EC private key (WIF, XPRV) must call this before encoding. If the key is invalid, the caller should try the next BIP85 index.
func ZeroBytes ¶
func ZeroBytes(buf []byte)
ZeroBytes overwrites buf with zeros. Use this to clear secret material (entropy, derived keys) returned by DeriveEntropy, DeriveKeyAndEntropy, and EntropyFromRawKey.
ZeroBytes is safe to call with nil or empty slices (no-op).
This is a best-effort measure. The Go garbage collector may have already copied the data to another location, so this is not a guarantee against memory forensics.
Types ¶
type DRNG ¶
type DRNG struct {
// contains filtered or unexported fields
}
DRNG is a deterministic random number generator seeded with BIP85 entropy. It implements io.Reader by wrapping SHAKE256 (FIPS 202).
BIP85-DRNG-SHAKE256 seeds a SHAKE256 XOF with the 64-byte HMAC-SHA512 output and produces an unlimited deterministic byte stream.
DRNG is forward-only: once bytes are read, they cannot be re-read. Create a new DRNG from the same entropy to restart the sequence.
A DRNG instance must not be shared between goroutines. Each goroutine must create its own instance.
func NewDRNG ¶
NewDRNG creates a BIP85-DRNG-SHAKE256 from 64 bytes of BIP85 entropy. The entropy is consumed immediately; the caller may zero it afterward.
Panics if entropy is not exactly 64 bytes (the caller has a bug).
Example ¶
key, err := bip85.ParseKey("xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb")
if err != nil {
log.Fatal(err)
}
defer key.Zero()
// Derive entropy and create a DRNG (deterministic random number generator).
path, _ := bip85.ParsePath("m/83696968'/0'/0'")
entropy, err := bip85.DeriveEntropy(key, path)
if err != nil {
log.Fatal(err)
}
defer bip85.ZeroBytes(entropy)
drng := bip85.NewDRNG(entropy)
// Read 16 bytes of deterministic output.
buf := make([]byte, 16)
drng.Read(buf)
fmt.Println(hex.EncodeToString(buf))
Output: b78b1ee6b345eae6836c2d53d33c64cd
func (*DRNG) Read ¶
Read fills p with deterministic bytes from the SHAKE256 stream. It always returns len(p), nil. DRNG never returns io.EOF.
Read is not safe for concurrent use. Each goroutine must use its own DRNG instance.
Read is suitable as a rand source for crypto/rsa.GenerateKey and similar functions that accept an io.Reader.
type Option ¶
type Option func(*derivationConfig)
Option configures the BIP85 derivation pipeline. Options are applied in order. Nil options are silently skipped. All options that modify cryptographic behavior produce non-standard output that will not match any reference BIP85 implementation.
func WithCustomDeriver ¶
func WithCustomDeriver(fn func(root *hdkeychain.ExtendedKey, path Path) ([]byte, error)) Option
WithCustomDeriver replaces the default BIP32 derivation with a custom function. The function receives the parsed root key and path, and must return a freshly allocated slice of raw private key material. The returned slice will be zeroed by the library after the HMAC step.
This option is only compatible with DeriveEntropy and DeriveKeyAndEntropy. It is rejected by EntropyFromRawKey, which accepts pre-derived key material directly.
Security: the deriver receives the full master key. Only use derivers from your own trust domain. A malicious deriver can read or copy the master key. Do not accept Options from untrusted sources.
func WithEntropyPostProcessor ¶
WithEntropyPostProcessor adds a post-processing step after the HMAC-SHA512 entropy extraction. The function receives the 64-byte entropy and must return at least 64 bytes. The result is copied to a fresh allocation before the original entropy is zeroed, so the post-processor may safely return a sub-slice of its input.
func WithHMACKey ¶
WithHMACKey overrides the default HMAC key ("bip-entropy-from-k"). The key must be non-nil and non-empty.
Setting a custom HMAC key produces non-standard output that will not match any reference BIP85 implementation.
type Path ¶
type Path struct {
// contains filtered or unexported fields
}
Path represents a validated BIP85 derivation path. All components are hardened. The purpose code (83696968') is always the first component.
The zero value is an empty path. Passing it to DeriveEntropy returns ErrIncompletePath. Construct paths with ParsePath or the builder functions (BIP39Path, WIFPath, HexPath, etc.).
A Path is immutable after construction. It is safe for concurrent use.
func BIP39Path ¶
BIP39Path returns a path for BIP39 mnemonic derivation. Language codes: 0=English, 1=Japanese, 2=Korean, 3=Spanish, 4=Chinese (Simplified), 5=Chinese (Traditional), 6=French, 7=Italian, 8=Czech, 9=Portuguese. Valid word counts: 12, 15, 18, 21, 24.
Path: m/83696968'/39'/{language}'/{words}'/{index}'.
Example ¶
// Build a path for deriving a 12-word English BIP39 mnemonic at index 0. path := bip85.BIP39Path(bip85.LangEnglish, 12, 0) fmt.Println(path.String())
Output: m/83696968'/39'/0'/12'/0'
func Base64Path ¶
Base64Path returns a path for Base64-encoded password derivation. pwdLen must be in [20, 86].
Path: m/83696968'/707764'/{pwdLen}'/{index}'.
func Base85Path ¶
Base85Path returns a path for RFC 1924 Base85-encoded password derivation. pwdLen must be in [10, 80].
Path: m/83696968'/707785'/{pwdLen}'/{index}'.
func CorePath ¶
CorePath returns a path for direct BIP85 derivation without a registered application: m/83696968'/{appCode}'/{index}'. Use the application-specific builders (BIP39Path, WIFPath, etc.) for standard BIP85 applications.
func DicePath ¶
DicePath returns a path for dice roll generation via rejection sampling. sides must be >= 2. rolls is the number of dice to roll.
Path: m/83696968'/89101'/{sides}'/{rolls}'/{index}'.
func HexPath ¶
HexPath returns a path for raw hex entropy derivation. numBytes must be in [16, 64].
Path: m/83696968'/128169'/{numBytes}'/{index}'.
func ParsePath ¶
ParsePath parses a BIP85 derivation path string. The path must start with "m/83696968'" and all components must be hardened (marked with ', h, H, or p).
Accepted formats:
m/83696968'/0'/0' m/83696968h/0h/0h m/83696968H/0H/0H m/83696968p/0p/0p
Example ¶
// All hardened marker styles are accepted and normalized.
p1, _ := bip85.ParsePath("m/83696968'/0'/0'")
p2, _ := bip85.ParsePath("m/83696968h/0h/0h")
fmt.Println(p1.String())
fmt.Println(p2.String())
Output: m/83696968'/0'/0' m/83696968'/0'/0'
func RSAPath ¶
RSAPath returns a path for RSA key generation via BIP85-DRNG. keyBits is the RSA key size (e.g., 2048, 4096).
Path: m/83696968'/828365'/{keyBits}'/{keyIndex}'.
func WIFPath ¶
WIFPath returns a path for HD-Seed WIF (compressed private key) derivation.
Path: m/83696968'/2'/{index}'.
func XPRVPath ¶
XPRVPath returns a path for BIP32 extended private key derivation. The derived entropy uses reversed field ordering per the BIP85 spec: first 32 bytes = chain code, second 32 bytes = private key.
Path: m/83696968'/32'/{index}'.
func (Path) Components ¶
Components returns the raw (un-hardened) path component values. The returned slice is a copy.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
basic
command
Command basic demonstrates deriving a BIP39 mnemonic from a BIP32 master key using go-bip85.
|
Command basic demonstrates deriving a BIP39 mnemonic from a BIP32 master key using go-bip85. |
|
dice
command
Command dice demonstrates using BIP85 DICE for deterministic PIN generation and alphanumeric password generation via dice-to-alphabet mapping.
|
Command dice demonstrates using BIP85 DICE for deterministic PIN generation and alphanumeric password generation via dice-to-alphabet mapping. |
|
drng
command
Command drng demonstrates using the BIP85-DRNG-SHAKE256 as an io.Reader for custom key generation.
|
Command drng demonstrates using the BIP85-DRNG-SHAKE256 as an io.Reader for custom key generation. |
|
multichain
command
Command multichain demonstrates go-bip85's chain-agnostic design using EntropyFromRawKey.
|
Command multichain demonstrates go-bip85's chain-agnostic design using EntropyFromRawKey. |
|
password
command
Command password demonstrates generating Base64 and Base85 passwords from BIP85 entropy.
|
Command password demonstrates generating Base64 and Base85 passwords from BIP85 entropy. |