@@ -18,7 +18,15 @@ use crate::workflow::confirm;
1818
1919use util:: bip32:: HARDENED ;
2020
21+ const PURPOSE : u32 = 44 + HARDENED ;
22+ const COIN_MAINNET : u32 = 60 + HARDENED ;
23+ const COIN_TESTNET : u32 = 1 + HARDENED ;
24+
2125const 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 ;
2230
2331/// If the second element of `keypath` does not match the expected bip44 coin value for the given
2432/// coin, we warn the user about an unusual keypath.
@@ -56,29 +64,30 @@ pub async fn warn_unusual_keypath(
5664}
5765
5866/// 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'
6270/// @return true if the keypath is valid, false if it is invalid.
6371pub 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+ }
6779}
6880
69- /// Does limit checks the keypath, whitelisting bip44 purpose, account and change .
81+ /// Does limit checks the keypath.
7082/// Returns true if the keypath is valid, false if it is invalid.
7183pub 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 ,
8090 }
81- true
8291}
8392
8493#[ cfg( test) ]
@@ -107,11 +116,7 @@ mod tests {
107116 0
108117 ] ) ) ;
109118 // 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 , ] ) ) ;
115120 // too long
116121 assert ! ( !is_valid_keypath_xpub( & [
117122 44 + HARDENED ,
@@ -120,6 +125,24 @@ mod tests {
120125 0 ,
121126 0
122127 ] ) ) ;
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+ ] ) ) ;
123146 }
124147
125148 #[ test]
@@ -175,10 +198,76 @@ mod tests {
175198 0
176199 ] ) ) ;
177200 // 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+ ] ) ) ;
182234 }
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+ ] ) ) ;
183272 }
184273}
0 commit comments