github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/chain/accounts/hd.go (about) 1 package accounts 2 3 import ( 4 "errors" 5 "fmt" 6 "math" 7 "math/big" 8 "strings" 9 ) 10 11 var DefaultRootDerivationPath = DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0} 12 13 var DefaultBaseDerivationPath = DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0, 0} 14 15 var DefaultLedgerBaseDerivationPath = DerivationPath{0x80000000 + 44, 0x80000000 + 60, 0x80000000 + 0, 0} 16 17 type DerivationPath []uint32 18 19 func ParseDerivationPath(path string) (DerivationPath, error) { 20 var result DerivationPath 21 22 components := strings.Split(path, "/") 23 switch { 24 case len(components) == 0: 25 return nil, errors.New("empty derivation path") 26 27 case strings.TrimSpace(components[0]) == "": 28 return nil, errors.New("ambiguous path: use 'm/' prefix for absolute paths, or no leading '/' for relative ones") 29 30 case strings.TrimSpace(components[0]) == "m": 31 components = components[1:] 32 33 default: 34 result = append(result, DefaultRootDerivationPath...) 35 } 36 37 if len(components) == 0 { 38 return nil, errors.New("empty derivation path") 39 } 40 for _, component := range components { 41 42 component = strings.TrimSpace(component) 43 var value uint32 44 45 if strings.HasSuffix(component, "'") { 46 value = 0x80000000 47 component = strings.TrimSpace(strings.TrimSuffix(component, "'")) 48 } 49 50 bigval, ok := new(big.Int).SetString(component, 0) 51 if !ok { 52 return nil, fmt.Errorf("invalid component: %s", component) 53 } 54 max := math.MaxUint32 - value 55 if bigval.Sign() < 0 || bigval.Cmp(big.NewInt(int64(max))) > 0 { 56 if value == 0 { 57 return nil, fmt.Errorf("component %v out of allowed range [0, %d]", bigval, max) 58 } 59 return nil, fmt.Errorf("component %v out of allowed hardened range [0, %d]", bigval, max) 60 } 61 value += uint32(bigval.Uint64()) 62 63 result = append(result, value) 64 } 65 return result, nil 66 } 67 68 func (path DerivationPath) String() string { 69 result := "m" 70 for _, component := range path { 71 var hardened bool 72 if component >= 0x80000000 { 73 component -= 0x80000000 74 hardened = true 75 } 76 result = fmt.Sprintf("%s/%d", result, component) 77 if hardened { 78 result += "'" 79 } 80 } 81 return result 82 }