@@ -18,7 +18,13 @@ use crate::workflow::confirm;
18
18
19
19
use util:: bip32:: HARDENED ;
20
20
21
+ const PURPOSE : u32 = 44 + HARDENED ;
22
+ const COIN_MAINNET : u32 = 60 + HARDENED ;
23
+ const COIN_TESTNET : u32 = 1 + HARDENED ;
24
+
21
25
const ACCOUNT_MAX : u32 = 99 ; // 100 accounts
26
+ const ACCOUNT_MIN_H : u32 = 0 + HARDENED ;
27
+ const ACCOUNT_MAX_H : u32 = ACCOUNT_MAX + HARDENED ;
22
28
23
29
/// If the second element of `keypath` does not match the expected bip44 coin value for the given
24
30
/// coin, we warn the user about an unusual keypath.
@@ -56,29 +62,30 @@ pub async fn warn_unusual_keypath(
56
62
}
57
63
58
64
/// Does limit checks the keypath, whitelisting bip44 purpose, account and change.
59
- /// Only allows the well-known xpubs of m'/44'/60'/0'/0 and m'/44'/1'/0'/0 for now.
60
- /// Since ethereum doesn't use the "change" path part it is always 0 and have become part of the
61
- /// xpub keypath.
65
+ /// Allows the following xpubs:
66
+ /// For BitBoxApp, MyEtherWalelt: m'/44'/60'/0'/0 and m'/44'/1'/0'/0.
67
+ /// For Ledger Live compatibility: m/44'/60'/account' and m/44'/1'/account'
62
68
/// @return true if the keypath is valid, false if it is invalid.
63
69
pub fn is_valid_keypath_xpub ( keypath : & [ u32 ] ) -> bool {
64
- keypath. len ( ) == 4
65
- && ( keypath[ ..4 ] == [ 44 + HARDENED , 60 + HARDENED , 0 + HARDENED , 0 ]
66
- || keypath[ ..4 ] == [ 44 + HARDENED , 1 + HARDENED , 0 + HARDENED , 0 ] )
70
+ match keypath {
71
+ // BitBoxApp, MyEtherWallet
72
+ [ PURPOSE , COIN_MAINNET | COIN_TESTNET , HARDENED , 0 ] => true ,
73
+ // Ledger Live
74
+ [ PURPOSE , COIN_MAINNET | COIN_TESTNET , ACCOUNT_MIN_H ..=ACCOUNT_MAX_H ] => true ,
75
+ _ => false ,
76
+ }
67
77
}
68
78
69
- /// Does limit checks the keypath, whitelisting bip44 purpose, account and change .
79
+ /// Does limit checks the keypath.
70
80
/// Returns true if the keypath is valid, false if it is invalid.
71
81
pub fn is_valid_keypath_address ( keypath : & [ u32 ] ) -> bool {
72
- if keypath. len ( ) != 5 {
73
- return false ;
82
+ match keypath {
83
+ // BitBoxApp, MyEtherWallet
84
+ [ PURPOSE , COIN_MAINNET | COIN_TESTNET , HARDENED , 0 , 0 ..=ACCOUNT_MAX ] => true ,
85
+ // Ledger Live
86
+ [ PURPOSE , COIN_MAINNET | COIN_TESTNET , ACCOUNT_MIN_H ..=ACCOUNT_MAX_H , 0 , 0 ] => true ,
87
+ _ => false ,
74
88
}
75
- if !is_valid_keypath_xpub ( & keypath[ ..4 ] ) {
76
- return false ;
77
- }
78
- if keypath[ 4 ] > ACCOUNT_MAX {
79
- return false ;
80
- }
81
- true
82
89
}
83
90
84
91
#[ cfg( test) ]
@@ -107,11 +114,7 @@ mod tests {
107
114
0
108
115
] ) ) ;
109
116
// too short
110
- assert ! ( !is_valid_keypath_xpub( & [
111
- 44 + HARDENED ,
112
- 60 + HARDENED ,
113
- 0 + HARDENED
114
- ] ) ) ;
117
+ assert ! ( !is_valid_keypath_xpub( & [ 44 + HARDENED , 60 + HARDENED , ] ) ) ;
115
118
// too long
116
119
assert ! ( !is_valid_keypath_xpub( & [
117
120
44 + HARDENED ,
@@ -120,6 +123,24 @@ mod tests {
120
123
0 ,
121
124
0
122
125
] ) ) ;
126
+
127
+ // Ledger Live
128
+ assert ! ( is_valid_keypath_xpub( & [
129
+ 44 + HARDENED ,
130
+ 60 + HARDENED ,
131
+ 0 + HARDENED ,
132
+ ] ) ) ;
133
+ assert ! ( is_valid_keypath_xpub( & [
134
+ 44 + HARDENED ,
135
+ 60 + HARDENED ,
136
+ 99 + HARDENED ,
137
+ ] ) ) ;
138
+ // account too high
139
+ assert ! ( !is_valid_keypath_xpub( & [
140
+ 44 + HARDENED ,
141
+ 60 + HARDENED ,
142
+ 100 + HARDENED ,
143
+ ] ) ) ;
123
144
}
124
145
125
146
#[ test]
@@ -175,10 +196,76 @@ mod tests {
175
196
0
176
197
] ) ) ;
177
198
// tweak keypath elements
178
- for i in 0 ..4 {
179
- let mut keypath = [ 44 + HARDENED , 60 + HARDENED , 0 + HARDENED , 0 , 0 ] ;
180
- keypath[ i] += 1 ;
181
- assert ! ( !is_valid_keypath_address( & keypath) ) ;
199
+ assert ! ( !is_valid_keypath_address( & [
200
+ 44 + HARDENED + 1 ,
201
+ 60 + HARDENED ,
202
+ 0 + HARDENED ,
203
+ 0 ,
204
+ 0
205
+ ] ) ) ;
206
+ assert ! ( !is_valid_keypath_address( & [
207
+ 44 + HARDENED ,
208
+ 60 + HARDENED + 1 ,
209
+ 0 + HARDENED ,
210
+ 0 ,
211
+ 0
212
+ ] ) ) ;
213
+ assert ! ( !is_valid_keypath_address( & [
214
+ 44 + HARDENED ,
215
+ 60 + HARDENED ,
216
+ 0 + HARDENED ,
217
+ 0 + 1 ,
218
+ 0
219
+ ] ) ) ;
220
+
221
+ // Ledger Live
222
+
223
+ // 100 good paths.
224
+ for account in 0 ..100 {
225
+ assert ! ( is_valid_keypath_address( & [
226
+ 44 + HARDENED ,
227
+ 60 + HARDENED ,
228
+ account + HARDENED ,
229
+ 0 ,
230
+ 0
231
+ ] ) ) ;
182
232
}
233
+ // account too high
234
+ assert ! ( !is_valid_keypath_address( & [
235
+ 44 + HARDENED ,
236
+ 60 + HARDENED ,
237
+ 100 + HARDENED ,
238
+ 0 ,
239
+ 0
240
+ ] ) ) ;
241
+ // tweak keypath elements
242
+ assert ! ( !is_valid_keypath_address( & [
243
+ 44 + HARDENED + 1 ,
244
+ 60 + HARDENED ,
245
+ 1 + HARDENED ,
246
+ 0 ,
247
+ 0
248
+ ] ) ) ;
249
+ assert ! ( !is_valid_keypath_address( & [
250
+ 44 + HARDENED ,
251
+ 60 + HARDENED + 1 ,
252
+ 1 + HARDENED ,
253
+ 0 ,
254
+ 0
255
+ ] ) ) ;
256
+ assert ! ( !is_valid_keypath_address( & [
257
+ 44 + HARDENED ,
258
+ 60 + HARDENED ,
259
+ 1 + HARDENED ,
260
+ 0 + 1 ,
261
+ 0
262
+ ] ) ) ;
263
+ assert ! ( !is_valid_keypath_address( & [
264
+ 44 + HARDENED ,
265
+ 60 + HARDENED ,
266
+ 1 + HARDENED ,
267
+ 0 ,
268
+ 0 + 1 ,
269
+ ] ) ) ;
183
270
}
184
271
}
0 commit comments