bip32

package module
v0.0.0-...-d0929ac Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 28, 2019 License: MIT Imports: 15 Imported by: 0

README

go-bip32

An implementation of the BIP32 spec for Hierarchical Deterministic Bitcoin addresses as a simple Go library. The semantics of derived keys are up to the user. BIP43 and BIP44 are good schemes to implement with this library. An additional library for either or both of those on top of this library should be developed.

Modified for use in Skycoin, derived from https://github.com/tyler-smith/go-bip32

Example

It's very unlikely, but possible, that a given index does not produce a valid private key. Error checking is skipped in this example for brevity but should be handled in real code. In such a case, an error of type Error is returned and it's method ImpossibleChild() will return true.

An example for handling this:

func tryNewPrivateKeyFromPath() (*bip32.PrivateKey, error) {
	k, err := bip32.NewPrivateKeyFromPath([]byte("abc123"), "m/1'/1'/0/1")
	if err != nil {
		if bip32.IsImpossibleChildError(err) {
			fmt.Println("Child number 1 generated an invalid key, use the next child number")
		}
		return err
	}

	return k, nil
}

Any valid private key will have a valid public key so that PrivateKey.PublicKey() method never returns an error.

package main

import (
	"github.com/skycoin/skycoin/src/cipher/bip32"
	"github.com/skycoin/skycoin/src/cipher/bip39"
	"fmt"
	"log"
)

// Example address creation for a fictitious company ComputerVoice Inc. where
// each department has their own wallet to manage
func main(){
	// Generate a mnemonic to determine all keys from. Don't lose it.
	mnemonic := bip39.MustNewDefaultMnemonic()

	// Derivce a seed from the mnemonic
	seed, err := bip39.NewSeed(mnemonic, "")
	if err != nil {
		log.Fatalln("Error generating seed:", err)
	}

	// Create master private key from seed
	computerVoiceMasterKey, err := bip32.NewMasterKey(seed)
	if err != nil {
		log.Fatalln("NewMasterKey failed:", err)
	}

	// Map departments to keys
	// There is a very small chance a given child index is invalid (less than 1 in 2^127)
	// If so your real program should handle this by skipping the index
	departmentKeys := map[string]*bip32.Key{}
	departmentKeys["Sales"], err = computerVoiceMasterKey.NewChildKey(0)
	if err != nil {
		log.Fatalln("NewChildKey:", err)
	}
	departmentKeys["Marketing"], err = computerVoiceMasterKey.NewChildKey(1)
	if err != nil {
		log.Fatalln("NewChildKey:", err)
	}
	departmentKeys["Engineering"], err = computerVoiceMasterKey.NewChildKey(2)
	if err != nil {
		log.Fatalln("NewChildKey:", err)
	}
	departmentKeys["Customer Support"], err = computerVoiceMasterKey.NewChildKey(3)
	if err != nil {
		log.Fatalln("NewChildKey:", err)
	}

	// Create public keys for record keeping, auditors, payroll, etc
	departmentAuditKeys := map[string]*bip32.Key{}
	departmentAuditKeys["Sales"] = departmentKeys["Sales"].PublicKey()
	departmentAuditKeys["Marketing"] = departmentKeys["Marketing"].PublicKey()
	departmentAuditKeys["Engineering"] = departmentKeys["Engineering"].PublicKey()
	departmentAuditKeys["Customer Support"] = departmentKeys["Customer Support"].PublicKey()

	// Print public keys
	for department, pubKey := range departmentAuditKeys {
		fmt.Println(department, pubKey)
	}
}

Thanks

The developers at Factom have contributed a lot to this library and have made many great improvements to it. Please check out their project(s) and give them a thanks if you use this library.

Thanks to bartekn from Stellar for some important bug catches.

Documentation

Overview

Package bip32 implements the bip32 spec https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki

Index

Constants

View Source
const (
	// FirstHardenedChild is the index of the firxt "hardened" child key as per the
	// bip32 spec
	FirstHardenedChild = uint32(0x80000000)
)

Variables

View Source
var (
	// PrivateWalletVersion is the version flag for serialized private keys ("xpriv")
	PrivateWalletVersion = []byte{0x04, 0x88, 0xAD, 0xE4}

	// PublicWalletVersion is the version flag for serialized public keys ("xpub")
	PublicWalletVersion = []byte{0x04, 0x88, 0xB2, 0x1E}

	// ErrSerializedKeyWrongSize is returned when trying to deserialize a key that
	// has an incorrect length
	ErrSerializedKeyWrongSize = NewError(errors.New("Serialized keys should be exactly 82 bytes"))

	// ErrHardenedChildPublicKey is returned when trying to create a harded child
	// of the public key
	ErrHardenedChildPublicKey = NewError(errors.New("Can't create hardened child for public key"))

	// ErrInvalidChecksum is returned when deserializing a key with an incorrect checksum
	ErrInvalidChecksum = NewError(errors.New("Checksum doesn't match"))

	// ErrDerivedInvalidPrivateKey is returned when an invalid private key was derived
	ErrDerivedInvalidPrivateKey = NewError(errors.New("Derived invalid private key"))

	// ErrDerivedInvalidPublicKey is returned when an invalid public key was derived
	ErrDerivedInvalidPublicKey = NewError(errors.New("Derived invalid public key"))

	// ErrInvalidPrivateKeyVersion is returned when a deserializing a private key without the 'xprv' prefix
	ErrInvalidPrivateKeyVersion = NewError(errors.New("Invalid private key version"))

	// ErrInvalidPublicKeyVersion is returned when a deserializing a public key without the 'xpub' prefix
	ErrInvalidPublicKeyVersion = NewError(errors.New("Invalid public key version"))

	// ErrInvalidSeedLength is returned when generating a master key with an invalid number of seed bits
	ErrInvalidSeedLength = NewError(errors.New("Invalid master key seed length"))

	// ErrDeserializePrivateFromPublic attempted to deserialize a private key from an encoded public key
	ErrDeserializePrivateFromPublic = NewError(errors.New("Cannot deserialize a private key from a public key"))

	// ErrInvalidKeyVersion is returned if the key version is not 'xpub' or 'xprv'
	ErrInvalidKeyVersion = NewError(errors.New("Invalid key version"))

	// ErrInvalidFingerprint is returned if a deserialized key has an invalid fingerprint
	ErrInvalidFingerprint = NewError(errors.New("Invalid key fingerprint"))

	// ErrInvalidChildNumber is returned if a deserialized key has an invalid child number
	ErrInvalidChildNumber = NewError(errors.New("Invalid key child number"))

	// ErrInvalidPrivateKey is returned if a deserialized xprv key's private key is invalid
	ErrInvalidPrivateKey = NewError(errors.New("Invalid private key"))

	// ErrInvalidPublicKey is returned if a deserialized xpub key's public key is invalid
	ErrInvalidPublicKey = NewError(errors.New("Invalid public key"))

	// ErrMaxDepthReached maximum allowed depth (255) reached for child key
	ErrMaxDepthReached = NewError(errors.New("Maximum child depth reached"))
)
View Source
var (
	// ErrPathNoMaster HD wallet path does not start with m
	ErrPathNoMaster = errors.New("Path must start with m")
	// ErrPathChildMaster HD wallet path contains m in a child node
	ErrPathChildMaster = errors.New("Path contains m as a child node")
	// ErrPathNodeNotNumber HD wallet path node is not a valid uint32 number
	ErrPathNodeNotNumber = errors.New("Path node is not a valid uint32 number")
	// ErrPathNodeNumberTooLarge HD wallet path node is >= 2^31
	ErrPathNodeNumberTooLarge = errors.New("Path node must be less than 2^31")
)

Functions

func IsImpossibleChildError

func IsImpossibleChildError(err error) bool

IsImpossibleChildError returns true if the error is an ImpossibleChild Error

func NewError

func NewError(err error) error

NewError creates an Error

func NewImpossibleChildError

func NewImpossibleChildError(err error, childNumber uint32) error

NewImpossibleChildError creates an Error flagged as an ImpossibleChild error

Types

type Error

type Error struct {
	// contains filtered or unexported fields
}

Error wraps bip32 errors

func (Error) ImpossibleChild

func (err Error) ImpossibleChild() bool

ImpossibleChild returns true if this error indicates that a given child number cannot produce a valid key. If the caller receives this error, they should skip this child and go to the next number. The probability of this happening is less than 1 in 2^127.

type Path

type Path struct {
	Elements []PathNode
}

Path represents a parsed HD wallet path

func ParsePath

func ParsePath(p string) (*Path, error)

ParsePath parses a bip32 HD wallet path. The path must start with m/.

type PathNode

type PathNode struct {
	Master      bool
	ChildNumber uint32
}

PathNode is an element of an HD wallet path

func (PathNode) Hardened

func (p PathNode) Hardened() bool

Hardened returns true if this path node is hardened

type PrivateKey

type PrivateKey struct {
	// contains filtered or unexported fields
}

PrivateKey represents a bip32 extended private key

func DeserializeEncodedPrivateKey

func DeserializeEncodedPrivateKey(xprv string) (*PrivateKey, error)

DeserializeEncodedPrivateKey deserializes a base58 xprv key to a PrivateKey

func DeserializePrivateKey

func DeserializePrivateKey(data []byte) (*PrivateKey, error)

DeserializePrivateKey deserializes the []byte serialization of a PrivateKey

func NewMasterKey

func NewMasterKey(seed []byte) (*PrivateKey, error)

NewMasterKey creates a new master extended key from a seed. Seed should be between 128 and 512 bits; 256 bits are recommended. https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#master-key-generation

func NewPrivateKeyFromPath

func NewPrivateKeyFromPath(seed []byte, p string) (*PrivateKey, error)

NewPrivateKeyFromPath returns a private key at a given bip32 path. The path must be a full path starting with m/, and the initial seed must be provided. This method can return an ImpossibleChild error.

func (PrivateKey) ChildNumber

func (k PrivateKey) ChildNumber() uint32

func (*PrivateKey) DeriveSubpath

func (k *PrivateKey) DeriveSubpath(nodes []PathNode) (*PrivateKey, error)

DeriveSubpath derives a PrivateKey at at bip32 subpath, e.g. `0'/1'/0`. The nodes argument must not be empty. This method can return an ImpossibleChild error.

func (*PrivateKey) Fingerprint

func (k *PrivateKey) Fingerprint() []byte

Fingerprint returns the key fingerprint

func (*PrivateKey) Identifier

func (k *PrivateKey) Identifier() []byte

Identifier returns the key ID

func (*PrivateKey) NewPrivateChildKey

func (k *PrivateKey) NewPrivateChildKey(childIdx uint32) (*PrivateKey, error)

NewPrivateChildKey derives a private child key from a given parent as outlined by bip32, CDKpriv(). https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#private-parent-key--private-child-key This method can return an ImpossibleChild error.

func (*PrivateKey) NewPublicChildKey

func (k *PrivateKey) NewPublicChildKey(childIdx uint32) (*PublicKey, error)

NewPublicChildKey derives a public child key from an extended public key, N(CKDpriv()). https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#private-parent-key--public-child-key This method can return an ImpossibleChild error.

func (*PrivateKey) PublicKey

func (k *PrivateKey) PublicKey() *PublicKey

PublicKey returns the public version of key or return a copy The 'Neuter' function from the bip32 spec, N((k, c) -> (K, c). https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#private-parent-key--public-child-key

func (*PrivateKey) Serialize

func (k *PrivateKey) Serialize() []byte

Serialize a Key to a 78 byte byte slice

func (*PrivateKey) String

func (k *PrivateKey) String() string

String encodes the Key in the standard Bitcoin base58 encoding

type PublicKey

type PublicKey struct {
	// contains filtered or unexported fields
}

PublicKey represents a bip32 extended public key

func DeserializeEncodedPublicKey

func DeserializeEncodedPublicKey(xpub string) (*PublicKey, error)

DeserializeEncodedPublicKey deserializes a base58 xpub key to a PublicKey

func DeserializePublicKey

func DeserializePublicKey(data []byte) (*PublicKey, error)

DeserializePublicKey deserializes the []byte serialization of a PublicKey

func (PublicKey) ChildNumber

func (k PublicKey) ChildNumber() uint32

func (*PublicKey) Fingerprint

func (k *PublicKey) Fingerprint() []byte

Fingerprint returns the key fingerprint

func (*PublicKey) Identifier

func (k *PublicKey) Identifier() []byte

Identifier returns the key ID

func (*PublicKey) NewPublicChildKey

func (k *PublicKey) NewPublicChildKey(childIdx uint32) (*PublicKey, error)

NewPublicChildKey derives a public child key from an extended public key, CKDpub(). Hardened child keys cannot be derived; the value of childIdx must be less than 2^31. https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#public-parent-key--public-child-key This method can return an ImpossibleChild error.

func (*PublicKey) Serialize

func (k *PublicKey) Serialize() []byte

Serialize a Key to a 78 byte byte slice

func (*PublicKey) String

func (k *PublicKey) String() string

String encodes the Key in the standard Bitcoin base58 encoding

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL