From 0620911e4670dc465faef83e108d6baf55b6bd7a Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 15 Aug 2020 18:25:54 +0200 Subject: [PATCH] core: allow spending coins from Bitcoin paths if the coin ... has implemented strong replay protection via SIGHASH_FORKID --- core/CHANGELOG.md | 2 ++ core/src/apps/bitcoin/keychain.py | 10 ++++++++ core/tests/test_apps.wallet.keychain.py | 34 ++++++++++++++++++++++++- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 26f7966c6a..7276e63bc5 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -16,6 +16,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Print inverted question mark for non-printable characters. - Remove pre-fill bar from text rendering functions. [#1173] - Display coin name when signing or verifying messages. [#1159] +- Allow spending coins from Bitcoin paths if the coin has implemented strong replay protection via `SIGHASH_FORKID`. [#1188] ### Deprecated @@ -269,3 +270,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). [#1159]: https://github.com/trezor/trezor-firmware/issues/1159 [#1165]: https://github.com/trezor/trezor-firmware/pull/1165 [#1173]: https://github.com/trezor/trezor-firmware/pull/1173 +[#1188]: https://github.com/trezor/trezor-firmware/issues/1188 diff --git a/core/src/apps/bitcoin/keychain.py b/core/src/apps/bitcoin/keychain.py index 24501689c3..6ad87b0af0 100644 --- a/core/src/apps/bitcoin/keychain.py +++ b/core/src/apps/bitcoin/keychain.py @@ -56,6 +56,16 @@ def get_namespaces_for_coin(coin: coininfo.CoinInfo): # m/0x4741b11e/6/pointer namespaces.append([0x4741B11E]) + # some wallets such as Electron-Cash (BCH) store coins on Bitcoin paths + # we can allow spending these coins from Bitcoin paths if the coin has + # implemented strong replay protection via SIGHASH_FORKID + if coin.fork_id is not None: + namespaces.append([44 | HARDENED, 0 | HARDENED]) + namespaces.append([48 | HARDENED, 0 | HARDENED]) + if coin.segwit: + namespaces.append([49 | HARDENED, 0 | HARDENED]) + namespaces.append([84 | HARDENED, 0 | HARDENED]) + return namespaces diff --git a/core/tests/test_apps.wallet.keychain.py b/core/tests/test_apps.wallet.keychain.py index e5f020cc07..6808992b05 100644 --- a/core/tests/test_apps.wallet.keychain.py +++ b/core/tests/test_apps.wallet.keychain.py @@ -87,14 +87,46 @@ class TestAltcoinKeychains(unittest.TestCase): self.assertFalse(coin.segwit) valid_addresses = ( [44 | HARDENED, 145 | HARDENED], + [44 | HARDENED, 0 | HARDENED], [45 | HARDENED, 123456], [48 | HARDENED, 145 | HARDENED], + [48 | HARDENED, 0 | HARDENED], ) invalid_addresses = ( [43 | HARDENED, 145 | HARDENED], - [44 | HARDENED, 0 | HARDENED], + [43 | HARDENED, 0 | HARDENED], [49 | HARDENED, 145 | HARDENED], + [49 | HARDENED, 0 | HARDENED], [84 | HARDENED, 145 | HARDENED], + [84 | HARDENED, 0 | HARDENED], + ) + + for addr in valid_addresses: + keychain.derive(addr) + + for addr in invalid_addresses: + self.assertRaises(wire.DataError, keychain.derive, addr) + + def test_litecoin(self): + keychain, coin = await_result( + get_keychain_for_coin(wire.DUMMY_CONTEXT, "Litecoin") + ) + self.assertEqual(coin.coin_name, "Litecoin") + + self.assertTrue(coin.segwit) + valid_addresses = ( + [44 | HARDENED, 2 | HARDENED], + [45 | HARDENED, 123456], + [48 | HARDENED, 2 | HARDENED], + [49 | HARDENED, 2 | HARDENED], + [84 | HARDENED, 2 | HARDENED], + ) + invalid_addresses = ( + [43 | HARDENED, 2 | HARDENED], + [44 | HARDENED, 0 | HARDENED], + [48 | HARDENED, 0 | HARDENED], + [49 | HARDENED, 0 | HARDENED], + [84 | HARDENED, 0 | HARDENED], ) for addr in valid_addresses: