hdwallet

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

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

Go to latest
Published: Dec 14, 2018 License: MIT Imports: 15 Imported by: 1

README

Simple Hierarchical Deterministic Wallet For Ether (Go Implementation)

Before get started

  1. Please first download go for testing.
  2. Download required packages (downloaded in terminal for Unix like system): source download-packages.sh
  3. Run tests: go test
  4. Run some demos in the ./demo/ repository with go run ./demo/<demo-name.go>

Very Simple Wallet and Hierarchical Deterministic (HD) Wallet Introduction

Purpose of Wallet
  • Used for storing the public and private key pairs of different cryptocurrencies.
  • Wallet can also be the platform or interface that be used for interacting with Decentralized Applications (DAPPs).
    • This is accomplished by creating, signing and broadcasting transactions that include smart contracts (or chaincode as called in Hyperledger) to update the states of decentralized applications (DAPPs) on some state machines built on blockchain, such as the EVM we used in Ethereum blockchain platform.
    • The Ethereum Virtual Machine (EVM) is a 256-bit Turing complete Virtual Machine that allows anyone to run Byte Code on it, which is also part of the Ethereum Protocol.
Wallet Types
  • Non-deterministic/Random Wallet
    • Pros: Very secure, since it will generate a new address and account for each new transaction.
    • Cons: But this is also a drawback when users need to backup the wallet: there are just too many accounts users need to manage and backup. And thus in practice, we normally never use a Non-deterministic wallet.
  • Hierarchical Deterministic (HD) Wallet
    • This is most used wallet type in the market, and it is called Hierarchical because of the level in its account structure:
      • 5-level path: m/purpose'/coin-type'/account'/change/address_index
    • Mnemonic code: these are 2^11 = 2048 phrases that is used to derive private keys, and it now supports multiple languages: BIP-39 Wordlists. You can find more information in the resources section.
    • BIP-32-39-43-44 provides an excellent guide line about how to design a HD-Wallet, here I will cover the based steps to generate Mnemonic Words and then generate new seed based on that (refer to Mastering Ethereum Chapter 5).
Generating Mnemonic Words
  1. Create a cryptographically random sequence S of 128 to 256 bits long.
  2. Create a checksum of S by taking the first length-of-S / 32 bits of the SHA-256 hash of S.
  3. Append this checksum to the end of the random sequence S.
  4. Divide the sequence-and-checksum concatenation into sections of 11 bits (each block has 11-bit).
  5. Map each of the 11-bit block/value to a phrase in the mnemonic dictionary (2,048 words).
  6. Create the mnemonic code from the sequence of words, and maintaining the order.
From Mnemonic To Seed
  1. Using the output the the step 6 from the Generating Mnemonic Words section as the input to the PBKDF2 key-stretching function.
  2. The second parameter to the PBKDF2 key-stretching function is a salt. The salt is composed of the string constant "mnemonic" concatenated with an optional user-supplied passphrase. 3. That's why we need to be very cautious about remembering the passphrase used to generate seed, cause it is included in each steps of cryptographical key generation. If we forgot it, then no body can help us to retrive the fund.
  3. PBKDF2 stretches the mnemonic and salt parameters using 2,048 rounds of hashing with the HMAC-SHA512 algorithm, producing a 512-bit value as its final output. That 512-bit value is the seed.
The Brain Wallet...

Normally all words are created randomly and presented to user after generated. (normally 12-24 words based on 128-256 bits of entropy. But Brain Wallet let users to generate the mnemonic words by themselve, which is obviously not a good idea. So we don't use brain wallet in real products normally.

The Art of Backup
  • The ideal goal of backing up is to never lose one bit of coin by losing devise or access to private keys, and at the same time prevent attackers gain any access to the private key or fund in the account.
  • In the Chapter 5 Wallet of Mastering Ethereum the authors covered a lot about good practice to backup wallet and some issues to consider when designing a wallet.

More resources

  • BIP-32: Hierarchical Deterministic Wallets
  • BIP-39: Mnemonic code for generating deterministic keys
  • BIP-43: Purpose Field for Deterministic Wallets
  • BIP-44: Multi-Account Hierarchy for Deterministic Wallets
  • BIP-70: Payment Protocol
  • BIP-75: Out of Band Address Exchange using Payment Protocol Encryption
  • BIP-115: Generic anti-replay protection using Script
  • EIP-55: Mixed-case checksum address encoding
  • EIP-155: Simple replay attack protection
Github Repos
GoDoc
Cryptography Tools And Blogs
Books

Documentation

Index

Constants

This section is empty.

Variables

View Source
var DefaultBaseDerivationPath = accounts.DefaultBaseDerivationPath

DefaultBaseDerivationPath is the base path from which custom derivation endpoints are incremented. As such, the first account will be at m/44'/60'/0'/0/0, the second at m/44'/60'/0'/0/1, etc.

View Source
var DefaultRootDerivationPath = accounts.DefaultRootDerivationPath

DefaultRootDerivationPath is the root path to which custom derivation endpoints are appended. As such, the first account will be at m/44'/60'/0'/0, the second at m/44'/60'/0'/1, etc.

Functions

func NewMnemonic

func NewMnemonic(bits int) (string, error)

Returns a randomly generated mnemonic phrase based on BIP-39. The following table describes the relation between the initial entropy length (ENT), which range from 128 to 256, the checksum length (CS) and the length of the generated mnemonic sentence (MS) in words.

CS = ENT / 32 MS = (ENT + CS) / 11

| ENT | CS | ENT+CS | MS | +-------+----+--------+------+ | 128 | 4 | 132 | 12 | | 160 | 5 | 165 | 15 | | 192 | 6 | 198 | 18 | | 224 | 7 | 231 | 21 | | 256 | 8 | 264 | 24 |

References: BIP-39:

https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki

Wordlist:

https://github.com/bitcoin/bips/blob/master/bip-0039/bip-0039-wordlists.md
Note: 	indexed from 1 to 2^11 = 2048 Mnemonic phrases options for eight
		different langauges

func NewSeed

func NewSeed() ([]byte, error)

Return a randomly generated seed based on BIP-39

func NewSeedFromMnemonic

func NewSeedFromMnemonic(mnemonic string) ([]byte, error)

Returns a new seed from BIP-39 mnemonic phrases.

func ParseDerivationPath

func ParseDerivationPath(path string) (accounts.DerivationPath, error)

Convert the derivation path string to []uint32

func StrictParseDerivationPath

func StrictParseDerivationPath(path string) accounts.DerivationPath

Same as the ParseDerivationPath(path string), but will be panic to any error

Types

type Wallet

type Wallet struct {
	// contains filtered or unexported fields
}
	---------------- Define the Wallet structure ----------------

	FILEDS:

	@mnemonic: a string of mnemonic phrase separated by spaces.

	@masterKey: ExtendedKey houses all the information needed to support a hierarchical
	deterministic extended key. See the package overview documentation for more
	details on how to use extended keys. We can use the IsPrivate function in
	hdkeychain package to determine whether an extended key is a private or
	public key.
	A private extended key can be used to derive both hardened and non-hardened
	(normal) child private and public extented key. Which can be used to prevent
	the case that exploiting one child key leads to the exploitation of all of
	its siblings.

	@seed: the byte array seed.

	@url: type URL struct {
    	Scheme string // Protocol scheme to identify a capable account backend
    	Path   string // Path for the backend to identify a unique entity
	}
	// Note: it doesn't do any URL encoding/decoding of special characters.

	@paths: map from common go-ethereum address type to derivation path type.
		type DerivationPath []uint32
	5 levels of hierarchies: m / purpose' / coin_type' / account' / change / address_index
	Note: see the "address structure" note above.
		type Address [AddressLength]byte
	Note: Address represents the 20 byte address of an Ethereum account.

	@accounts: type Account struct {
	    Address common.Address `json:"address"` // Ethereum account address derived from the key
	    URL     URL            `json:"url"`     // Optional resource locator within a backend
	}

	@stateLock: reader/writer mutual exclusion lock that can be held by an arbitrary number
	of readers or a single writer. The zero value for a RWMutex is an unlocked mutex.
	Note: A RWMutex must not be copied after first use.

func NewFromMnemonic

func NewFromMnemonic(mnemonic string) (*Wallet, error)

INPUT: @mnemonic: the mnemonic phrases string seperated by whitespaces.

OUTPUT: Returns a new wallet from a BIP-39 mnemonic.

func NewFromSeed

func NewFromSeed(seed []byte) (*Wallet, error)

INPUT: @seed: an array of seeds used for generating a new wallet

OUTPUT: Returns a new wallet based on the given seed

func (*Wallet) Accounts

func (w *Wallet) Accounts() []accounts.Account

Retrieves the list of signing accounts the wallet currently holds. For the hierarchical deterministic wallets, this list will only display the accounts be explicitly pinned during account derivation.

func (*Wallet) Address

func (w *Wallet) Address(account accounts.Account) (common.Address, error)

Return the address of the account, which is derived from the public key.

func (*Wallet) AddressBytes

func (w *Wallet) AddressBytes(account accounts.Account) ([]byte, error)

Return the address in byte format.

func (*Wallet) AddressHex

func (w *Wallet) AddressHex(account accounts.Account) (string, error)

Return the address in hexadecimal format.

func (*Wallet) Close

func (w *Wallet) Close() error

Close an opened wallet and release any used resources by the instance.

func (*Wallet) Contains

func (w *Wallet) Contains(account accounts.Account) bool

Returns whether the given account is contained in this particular wallet.

func (*Wallet) Derive

func (w *Wallet) Derive(path accounts.DerivationPath, pin bool) (accounts.Account, error)

@path: the path to be used to derive a hierarchical deterministic account. @pin: determine if this new account will be pinned to the wallet's tracking

account list.

func (*Wallet) Open

func (w *Wallet) Open(passphrase string) error

Open the wallet instance and build access. Not used for unlocking or decrypting account keys.

@passphrase: In the hard ware wallet implementation, the pass phrase in here is optional, and can be empty.

Note: need to be manually closed to free the allocated resources, esp. for hardware wallets.

func (*Wallet) Path

func (w *Wallet) Path(account accounts.Account) (string, error)

Return the derivation path of the given account

func (*Wallet) PrivateKey

func (w *Wallet) PrivateKey(account accounts.Account) (*ecdsa.PrivateKey, error)

@account: using this account to derivate the private key. Obtain the private key through the ECDSA (Elliptic Curve Digital Signature Algorithm)

func (*Wallet) PrivateKeyBytes

func (w *Wallet) PrivateKeyBytes(account accounts.Account) ([]byte, error)

@account: using this account to derivate the private key. Returns the ECDSA private key in bytes format.

func (*Wallet) PrivateKeyHex

func (w *Wallet) PrivateKeyHex(account accounts.Account) (string, error)

@account: using this account to derivate the private key. Returns the ECDSA private key in hexadecimal format.

func (*Wallet) PublicKey

func (w *Wallet) PublicKey(account accounts.Account) (*ecdsa.PublicKey, error)

Returns the public key of the account based on the ECDSA.

func (*Wallet) PublicKeyBytes

func (w *Wallet) PublicKeyBytes(account accounts.Account) ([]byte, error)

Returns the public key of the account based on the ECDSA in bytes format.

func (*Wallet) PublicKeyHex

func (w *Wallet) PublicKeyHex(account accounts.Account) (string, error)

Returns the public key of the account based on the ECDSA in hexadecimal format.

func (*Wallet) SelfDerive

func (w *Wallet) SelfDerive(base accounts.DerivationPath, chain ethereum.ChainStateReader)

@path: the path to be used to derive a hierarchical deterministic account. @chain: ChainStateReader wraps access to the state trie of the canonical blockchain. Reference to the interface:

https://github.com/ethereum/go-ethereum/blob/master/interfaces.go

Sets a base account derivation path from which the wallet tries to discover non zero accounts and automatically add them to the list of tracking accounts.

func (*Wallet) SignHash

func (w *Wallet) SignHash(account accounts.Account, hash []byte) ([]byte, error)

Requests the wallet to sign the given hash with the account.

func (*Wallet) SignHashWithPassphrase

func (w *Wallet) SignHashWithPassphrase(account accounts.Account, passphrase string, hash []byte) ([]byte, error)

Request the wallet to sign the given hash with the account. Using the passphrase as an extra layer of authetication information.

func (*Wallet) SignTx

func (w *Wallet) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error)

Using the account and chainID to sign the given transaction tx.

func (*Wallet) SignTxWithPassphrase

func (w *Wallet) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error)

Requests the wallet to sign the given transaction with the given passphrase as an extra layer of authetication information.

func (*Wallet) Status

func (w *Wallet) Status() (string, error)

Returning a custom status message to help the user in the current state of the wallet.

func (*Wallet) URL

func (w *Wallet) URL() accounts.URL

URL retrieves the canonical path under which this wallet is reachable. Used mainly on hardware devices.

func (*Wallet) Unpin

func (w *Wallet) Unpin(account accounts.Account) error

Helper function to unpins the account from list of pinned accounts

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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