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 }