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