@@ -18,7 +18,13 @@ 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 ;
2228
2329/// If the second element of `keypath` does not match the expected bip44 coin value for the given
2430/// coin, we warn the user about an unusual keypath.
@@ -56,29 +62,30 @@ pub async fn warn_unusual_keypath(
5662}
5763
5864/// 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'
6268/// @return true if the keypath is valid, false if it is invalid.
6369pub 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+ }
6777}
6878
69- /// Does limit checks the keypath, whitelisting bip44 purpose, account and change .
79+ /// Does limit checks the keypath.
7080/// Returns true if the keypath is valid, false if it is invalid.
7181pub 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 ,
7488 }
75- if !is_valid_keypath_xpub ( & keypath[ ..4 ] ) {
76- return false ;
77- }
78- if keypath[ 4 ] > ACCOUNT_MAX {
79- return false ;
80- }
81- true
8289}
8390
8491#[ cfg( test) ]
@@ -107,11 +114,7 @@ mod tests {
107114 0
108115 ] ) ) ;
109116 // 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 , ] ) ) ;
115118 // too long
116119 assert ! ( !is_valid_keypath_xpub( & [
117120 44 + HARDENED ,
@@ -120,6 +123,24 @@ mod tests {
120123 0 ,
121124 0
122125 ] ) ) ;
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+ ] ) ) ;
123144 }
124145
125146 #[ test]
@@ -175,10 +196,76 @@ mod tests {
175196 0
176197 ] ) ) ;
177198 // 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+ ] ) ) ;
182232 }
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+ ] ) ) ;
183270 }
184271}
0 commit comments