github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/crypto/hd/hdpath_test.go (about) 1 package hd 2 3 import ( 4 "encoding/hex" 5 "fmt" 6 "testing" 7 8 "github.com/gnolang/gno/tm2/pkg/crypto/bip39" 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/require" 11 ) 12 13 var defaultBIP39Passphrase = "" 14 15 // return bip39 seed with empty passphrase 16 func mnemonicToSeed(mnemonic string) []byte { 17 return bip39.NewSeed(mnemonic, defaultBIP39Passphrase) 18 } 19 20 func ExampleStringifyPathParams() { 21 path := NewParams(44, 0, 0, false, 0) 22 fmt.Println(path.String()) 23 path = NewParams(44, 33, 7, true, 9) 24 fmt.Println(path.String()) 25 // Output: 26 // 44'/0'/0'/0/0 27 // 44'/33'/7'/1/9 28 } 29 30 // from cosmos-sdk/types/address.go 31 const ( 32 testCoinType = 118 33 testFullFundraiserPath = "44'/118'/0'/0/0" 34 ) 35 36 func TestStringifyFundraiserPathParams(t *testing.T) { 37 t.Parallel() 38 39 path := NewFundraiserParams(4, testCoinType, 22) 40 require.Equal(t, "44'/118'/4'/0/22", path.String()) 41 42 path = NewFundraiserParams(4, testCoinType, 57) 43 require.Equal(t, "44'/118'/4'/0/57", path.String()) 44 45 path = NewFundraiserParams(4, 12345, 57) 46 require.Equal(t, "44'/12345'/4'/0/57", path.String()) 47 } 48 49 func TestPathToArray(t *testing.T) { 50 t.Parallel() 51 52 path := NewParams(44, 118, 1, false, 4) 53 require.Equal(t, "[44 118 1 0 4]", fmt.Sprintf("%v", path.DerivationPath())) 54 55 path = NewParams(44, 118, 2, true, 15) 56 require.Equal(t, "[44 118 2 1 15]", fmt.Sprintf("%v", path.DerivationPath())) 57 } 58 59 func TestParamsFromPath(t *testing.T) { 60 t.Parallel() 61 62 goodCases := []struct { 63 params *BIP44Params 64 path string 65 }{ 66 {&BIP44Params{44, 0, 0, false, 0}, "44'/0'/0'/0/0"}, 67 {&BIP44Params{44, 1, 0, false, 0}, "44'/1'/0'/0/0"}, 68 {&BIP44Params{44, 0, 1, false, 0}, "44'/0'/1'/0/0"}, 69 {&BIP44Params{44, 0, 0, true, 0}, "44'/0'/0'/1/0"}, 70 {&BIP44Params{44, 0, 0, false, 1}, "44'/0'/0'/0/1"}, 71 {&BIP44Params{44, 1, 1, true, 1}, "44'/1'/1'/1/1"}, 72 {&BIP44Params{44, 118, 52, true, 41}, "44'/118'/52'/1/41"}, 73 } 74 75 for i, c := range goodCases { 76 params, err := NewParamsFromPath(c.path) 77 errStr := fmt.Sprintf("%d %v", i, c) 78 assert.NoError(t, err, errStr) 79 assert.EqualValues(t, c.params, params, errStr) 80 assert.Equal(t, c.path, c.params.String()) 81 } 82 83 badCases := []struct { 84 path string 85 }{ 86 {"43'/0'/0'/0/0"}, // doesn't start with 44 87 {"44'/1'/0'/0/0/5"}, // too many fields 88 {"44'/0'/1'/0"}, // too few fields 89 {"44'/0'/0'/2/0"}, // change field can only be 0/1 90 {"44/0'/0'/0/0"}, // first field needs ' 91 {"44'/0/0'/0/0"}, // second field needs ' 92 {"44'/0'/0/0/0"}, // third field needs ' 93 {"44'/0'/0'/0'/0"}, // fourth field must not have ' 94 {"44'/0'/0'/0/0'"}, // fifth field must not have ' 95 {"44'/-1'/0'/0/0"}, // no negatives 96 {"44'/0'/0'/-1/0"}, // no negatives 97 {"a'/0'/0'/-1/0"}, // valid values 98 {"0/X/0'/-1/0"}, // valid values 99 {"44'/0'/X/-1/0"}, // valid values 100 {"44'/0'/0'/%/0"}, // valid values 101 {"44'/0'/0'/0/%"}, // valid values 102 } 103 104 for i, c := range badCases { 105 params, err := NewParamsFromPath(c.path) 106 errStr := fmt.Sprintf("%d %v", i, c) 107 assert.Nil(t, params, errStr) 108 assert.Error(t, err, errStr) 109 } 110 } 111 112 func ExampleSomeBIP32TestVecs() { 113 seed := mnemonicToSeed("barrel original fuel morning among eternal " + 114 "filter ball stove pluck matrix mechanic") 115 master, ch := ComputeMastersFromSeed(seed) 116 fmt.Println("keys from fundraiser test-vector (cosmos, bitcoin, ether)") 117 fmt.Println() 118 // cosmos 119 priv, err := DerivePrivateKeyForPath(master, ch, testFullFundraiserPath) 120 if err != nil { 121 fmt.Println("INVALID") 122 } else { 123 fmt.Println(hex.EncodeToString(priv[:])) 124 } 125 // bitcoin 126 priv, err = DerivePrivateKeyForPath(master, ch, "44'/0'/0'/0/0") 127 if err != nil { 128 fmt.Println("INVALID") 129 } else { 130 fmt.Println(hex.EncodeToString(priv[:])) 131 } 132 // ether 133 priv, err = DerivePrivateKeyForPath(master, ch, "44'/60'/0'/0/0") 134 if err != nil { 135 fmt.Println("INVALID") 136 } else { 137 fmt.Println(hex.EncodeToString(priv[:])) 138 } 139 // INVALID 140 priv, err = DerivePrivateKeyForPath(master, ch, "X/0'/0'/0/0") 141 if err != nil { 142 fmt.Println("INVALID") 143 } else { 144 fmt.Println(hex.EncodeToString(priv[:])) 145 } 146 priv, err = DerivePrivateKeyForPath(master, ch, "-44/0'/0'/0/0") 147 if err != nil { 148 fmt.Println("INVALID") 149 } else { 150 fmt.Println(hex.EncodeToString(priv[:])) 151 } 152 153 fmt.Println() 154 fmt.Println("keys generated via https://coinomi.com/recovery-phrase-tool.html") 155 fmt.Println() 156 157 seed = mnemonicToSeed( 158 "advice process birth april short trust crater change bacon monkey medal garment " + 159 "gorilla ranch hour rival razor call lunar mention taste vacant woman sister") 160 master, ch = ComputeMastersFromSeed(seed) 161 priv, _ = DerivePrivateKeyForPath(master, ch, "44'/1'/1'/0/4") 162 fmt.Println(hex.EncodeToString(priv[:])) 163 164 seed = mnemonicToSeed("idea naive region square margin day captain habit " + 165 "gun second farm pact pulse someone armed") 166 master, ch = ComputeMastersFromSeed(seed) 167 priv, _ = DerivePrivateKeyForPath(master, ch, "44'/0'/0'/0/420") 168 fmt.Println(hex.EncodeToString(priv[:])) 169 170 fmt.Println() 171 fmt.Println("BIP 32 example") 172 fmt.Println() 173 174 // bip32 path: m/0/7 175 seed = mnemonicToSeed("monitor flock loyal sick object grunt duty ride develop assault harsh history") 176 master, ch = ComputeMastersFromSeed(seed) 177 priv, _ = DerivePrivateKeyForPath(master, ch, "0/7") 178 fmt.Println(hex.EncodeToString(priv[:])) 179 180 // Output: keys from fundraiser test-vector (cosmos, bitcoin, ether) 181 // 182 // bfcb217c058d8bbafd5e186eae936106ca3e943889b0b4a093ae13822fd3170c 183 // e77c3de76965ad89997451de97b95bb65ede23a6bf185a55d80363d92ee37c3d 184 // 7fc4d8a8146dea344ba04c593517d3f377fa6cded36cd55aee0a0bb968e651bc 185 // INVALID 186 // INVALID 187 // 188 // keys generated via https://coinomi.com/recovery-phrase-tool.html 189 // 190 // a61f10c5fecf40c084c94fa54273b6f5d7989386be4a37669e6d6f7b0169c163 191 // 32c4599843de3ef161a629a461d12c60b009b676c35050be5f7ded3a3b23501f 192 // 193 // BIP 32 example 194 // 195 // c4c11d8c03625515905d7e89d25dfc66126fbc629ecca6db489a1a72fc4bda78 196 }