github.com/digdeepmining/go-atheios@v1.5.13-0.20180902133602-d5687a2e6f43/accounts/hd.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package accounts
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"math"
    23  	"math/big"
    24  	"strings"
    25  )
    26  
    27  // DefaultRootDerivationPath is the root path to which custom derivation endpoints
    28  // are appended. As such, the first account will be at m/44'/108'/0'/0, the second
    29  // at m/44'/108'/0'/1, etc.
    30  var DefaultRootDerivationPath = DerivationPath{0x80000000 + 44, 0x80000000 + 108, 0x80000000 + 0}
    31  
    32  // DefaultBaseDerivationPath is the base path from which custom derivation endpoints
    33  // are incremented. As such, the first account will be at m/44'/108'/0'/0, the second
    34  // at m/44'/108'/0'/1, etc.
    35  var DefaultBaseDerivationPath = DerivationPath{0x80000000 + 44, 0x80000000 + 108, 0x80000000 + 0, 0}
    36  
    37  // DerivationPath represents the computer friendly version of a hierarchical
    38  // deterministic wallet account derivation path.
    39  //
    40  // The BIP-32 spec https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
    41  // defines derivation paths to be of the form:
    42  //
    43  //   m / purpose' / coin_type' / account' / change / address_index
    44  //
    45  // The BIP-44 spec https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
    46  // defines that the `purpose` be 44' (or 0x8000002C) for crypto currencies, and
    47  // SLIP-44 https://github.com/satoshilabs/slips/blob/master/slip-0044.md assigns
    48  // the `coin_type` 108' (or 0x8000006C) to gath.
    49  //
    50  // The root path for gath is m/44'/108'/0'/0 according to the specification
    51  // from https://github.com/ethereum/EIPs/issues/84, albeit it's not set in stone
    52  // yet whether accounts should increment the last component or the children of
    53  // that. We will go with the simpler approach of incrementing the last component.
    54  type DerivationPath []uint32
    55  
    56  // ParseDerivationPath converts a user specified derivation path string to the
    57  // internal binary representation.
    58  //
    59  // Full derivation paths need to start with the `m/` prefix, relative derivation
    60  // paths (which will get appended to the default root path) must not have prefixes
    61  // in front of the first element. Whitespace is ignored.
    62  func ParseDerivationPath(path string) (DerivationPath, error) {
    63  	var result DerivationPath
    64  
    65  	// Handle absolute or relative paths
    66  	components := strings.Split(path, "/")
    67  	switch {
    68  	case len(components) == 0:
    69  		return nil, errors.New("empty derivation path")
    70  
    71  	case strings.TrimSpace(components[0]) == "":
    72  		return nil, errors.New("ambiguous path: use 'm/' prefix for absolute paths, or no leading '/' for relative ones")
    73  
    74  	case strings.TrimSpace(components[0]) == "m":
    75  		components = components[1:]
    76  
    77  	default:
    78  		result = append(result, DefaultRootDerivationPath...)
    79  	}
    80  	// All remaining components are relative, append one by one
    81  	if len(components) == 0 {
    82  		return nil, errors.New("empty derivation path") // Empty relative paths
    83  	}
    84  	for _, component := range components {
    85  		// Ignore any user added whitespace
    86  		component = strings.TrimSpace(component)
    87  		var value uint32
    88  
    89  		// Handle hardened paths
    90  		if strings.HasSuffix(component, "'") {
    91  			value = 0x80000000
    92  			component = strings.TrimSpace(strings.TrimSuffix(component, "'"))
    93  		}
    94  		// Handle the non hardened component
    95  		bigval, ok := new(big.Int).SetString(component, 0)
    96  		if !ok {
    97  			return nil, fmt.Errorf("invalid component: %s", component)
    98  		}
    99  		max := math.MaxUint32 - value
   100  		if bigval.Sign() < 0 || bigval.Cmp(big.NewInt(int64(max))) > 0 {
   101  			if value == 0 {
   102  				return nil, fmt.Errorf("component %v out of allowed range [0, %d]", bigval, max)
   103  			}
   104  			return nil, fmt.Errorf("component %v out of allowed hardened range [0, %d]", bigval, max)
   105  		}
   106  		value += uint32(bigval.Uint64())
   107  
   108  		// Append and repeat
   109  		result = append(result, value)
   110  	}
   111  	return result, nil
   112  }
   113  
   114  // String implements the stringer interface, converting a binary derivation path
   115  // to its canonical representation.
   116  func (path DerivationPath) String() string {
   117  	result := "m"
   118  	for _, component := range path {
   119  		var hardened bool
   120  		if component >= 0x80000000 {
   121  			component -= 0x80000000
   122  			hardened = true
   123  		}
   124  		result = fmt.Sprintf("%s/%d", result, component)
   125  		if hardened {
   126  			result += "'"
   127  		}
   128  	}
   129  	return result
   130  }