diff --git a/common/defs/ethereum/released-definitions-timestamp.txt b/common/defs/ethereum/released-definitions-timestamp.txt index ef8fc1c099..4366364f6a 100644 --- a/common/defs/ethereum/released-definitions-timestamp.txt +++ b/common/defs/ethereum/released-definitions-timestamp.txt @@ -1 +1 @@ -2025-02-07T18:39:08+00:00 +2025-03-04T12:16:03+00:00 diff --git a/common/releases.json b/common/releases.json index 2f55bdf725..3d7f117d44 100644 --- a/common/releases.json +++ b/common/releases.json @@ -43,6 +43,7 @@ "1.11.2": ["T1B1"], "1.12.1": ["T1B1"], "1.13.0": ["T1B1"], + "1.13.1": ["T1B1"], "2.0.5": ["T2T1"], "2.0.6": ["T2T1"], "2.0.7": ["T2T1"], @@ -80,6 +81,7 @@ "2.8.3": ["T3B1", "T3T1"], "2.8.7": ["T2B1", "T2T1", "T3B1", "T3T1"], "2.8.8": ["T2T1"], - "2.8.9": ["T2B1", "T2T1", "T3B1", "T3T1"] + "2.8.9": ["T2B1", "T2T1", "T3B1", "T3T1"], + "2.8.10": ["T2B1", "T2T1", "T3B1", "T3T1"] } } diff --git a/core/.changelog.d/4160.added b/core/.changelog.d/4160.added deleted file mode 100644 index 7879e132f6..0000000000 --- a/core/.changelog.d/4160.added +++ /dev/null @@ -1 +0,0 @@ -Add Nostr support (in debug mode only!). diff --git a/core/.changelog.d/4623.fixed b/core/.changelog.d/4623.fixed deleted file mode 100644 index 83b0daa82b..0000000000 --- a/core/.changelog.d/4623.fixed +++ /dev/null @@ -1 +0,0 @@ -Replaced "next page" icon with "..." ellipsis when confirming long message. diff --git a/core/.changelog.d/4771.fixed b/core/.changelog.d/4771.fixed deleted file mode 100644 index 9e01503faa..0000000000 --- a/core/.changelog.d/4771.fixed +++ /dev/null @@ -1 +0,0 @@ -[T2T1] Fixed upgrade confirmation text overflow. diff --git a/core/.changelog.d/4786.fixed b/core/.changelog.d/4786.fixed deleted file mode 100644 index dd3d5a4196..0000000000 --- a/core/.changelog.d/4786.fixed +++ /dev/null @@ -1 +0,0 @@ -[T2T1] Fixed Solana staking dialog fonts. diff --git a/core/.changelog.d/4787.fixed b/core/.changelog.d/4787.fixed deleted file mode 100644 index 32c7a22d86..0000000000 --- a/core/.changelog.d/4787.fixed +++ /dev/null @@ -1 +0,0 @@ -[T2B1,T3B1] Fixed Solana staking dialog title. diff --git a/core/.changelog.d/4819.fixed b/core/.changelog.d/4819.fixed deleted file mode 100644 index 7597f3b214..0000000000 --- a/core/.changelog.d/4819.fixed +++ /dev/null @@ -1 +0,0 @@ -Updated EIP-1559 fee-related labels. diff --git a/core/.changelog.d/4827.fixed b/core/.changelog.d/4827.fixed deleted file mode 100644 index 168b6998ef..0000000000 --- a/core/.changelog.d/4827.fixed +++ /dev/null @@ -1 +0,0 @@ -Allow firmware upgrade even if language change failed. diff --git a/core/.changelog.d/4964.added b/core/.changelog.d/4964.added deleted file mode 100644 index 62d1556cc0..0000000000 --- a/core/.changelog.d/4964.added +++ /dev/null @@ -1 +0,0 @@ -[T3T1] Visual cues to distinguish unlocked state on Homescreen. diff --git a/core/CHANGELOG.T2B1.md b/core/CHANGELOG.T2B1.md index 3885f1c296..0e2271e91c 100644 --- a/core/CHANGELOG.T2B1.md +++ b/core/CHANGELOG.T2B1.md @@ -4,6 +4,20 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [2.8.10] (21st May 2025) + +### Added +- Add Nostr support (in debug mode only!). [#4160] +- Solana: rent fee calculation [#4933] +- Solana: loadable token definitions [#3541] + +### Fixed +- Replaced "next page" icon with "..." ellipsis when confirming long message. [#4623] +- Fixed Solana staking dialog title. [#4787] +- Updated EIP-1559 fee-related labels. [#4819] +- Allow firmware upgrade even if language change failed. [#4827] +- Solana: fees calculation is now exact [#4965] + ## [2.8.9] (19th March 2025) ### Added @@ -1033,6 +1047,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). [#4142]: https://github.com/trezor/trezor-firmware/pull/4142 [#4151]: https://github.com/trezor/trezor-firmware/pull/4151 [#4155]: https://github.com/trezor/trezor-firmware/pull/4155 +[#4160]: https://github.com/trezor/trezor-firmware/pull/4160 [#4161]: https://github.com/trezor/trezor-firmware/pull/4161 [#4165]: https://github.com/trezor/trezor-firmware/pull/4165 [#4167]: https://github.com/trezor/trezor-firmware/pull/4167 @@ -1057,4 +1072,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). [#4541]: https://github.com/trezor/trezor-firmware/pull/4541 [#4560]: https://github.com/trezor/trezor-firmware/pull/4560 [#4571]: https://github.com/trezor/trezor-firmware/pull/4571 -[#1658739]: https://github.com/trezor/trezor-firmware/pull/1658739 +[#4623]: https://github.com/trezor/trezor-firmware/pull/4623 +[#4665]: https://github.com/trezor/trezor-firmware/pull/4665 +[#4771]: https://github.com/trezor/trezor-firmware/pull/4771 +[#4786]: https://github.com/trezor/trezor-firmware/pull/4786 +[#4787]: https://github.com/trezor/trezor-firmware/pull/4787 +[#4819]: https://github.com/trezor/trezor-firmware/pull/4819 +[#4827]: https://github.com/trezor/trezor-firmware/pull/4827 +[#4964]: https://github.com/trezor/trezor-firmware/pull/4964 diff --git a/core/CHANGELOG.T2T1.md b/core/CHANGELOG.T2T1.md index 448a03cf16..d4d41243e9 100644 --- a/core/CHANGELOG.T2T1.md +++ b/core/CHANGELOG.T2T1.md @@ -4,6 +4,21 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [2.8.10] (21st May 2025) + +### Added +- Add Nostr support (in debug mode only!). [#4160] +- Solana: rent fee calculation [#4933] +- Solana: loadable token definitions [#3541] + +### Fixed +- Replaced "next page" icon with "..." ellipsis when confirming long message. [#4623] +- Fixed upgrade confirmation text overflow. [#4771] +- Fixed Solana staking dialog fonts. [#4786] +- Updated EIP-1559 fee-related labels. [#4819] +- Allow firmware upgrade even if language change failed. [#4827] +- Solana: fees calculation is now exact [#4965] + ## [2.8.9] (19th March 2025) ### Added @@ -1031,6 +1046,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). [#4142]: https://github.com/trezor/trezor-firmware/pull/4142 [#4151]: https://github.com/trezor/trezor-firmware/pull/4151 [#4155]: https://github.com/trezor/trezor-firmware/pull/4155 +[#4160]: https://github.com/trezor/trezor-firmware/pull/4160 [#4161]: https://github.com/trezor/trezor-firmware/pull/4161 [#4165]: https://github.com/trezor/trezor-firmware/pull/4165 [#4167]: https://github.com/trezor/trezor-firmware/pull/4167 @@ -1055,4 +1071,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). [#4541]: https://github.com/trezor/trezor-firmware/pull/4541 [#4560]: https://github.com/trezor/trezor-firmware/pull/4560 [#4571]: https://github.com/trezor/trezor-firmware/pull/4571 -[#1658739]: https://github.com/trezor/trezor-firmware/pull/1658739 +[#4623]: https://github.com/trezor/trezor-firmware/pull/4623 +[#4665]: https://github.com/trezor/trezor-firmware/pull/4665 +[#4771]: https://github.com/trezor/trezor-firmware/pull/4771 +[#4786]: https://github.com/trezor/trezor-firmware/pull/4786 +[#4787]: https://github.com/trezor/trezor-firmware/pull/4787 +[#4819]: https://github.com/trezor/trezor-firmware/pull/4819 +[#4827]: https://github.com/trezor/trezor-firmware/pull/4827 +[#4964]: https://github.com/trezor/trezor-firmware/pull/4964 diff --git a/core/CHANGELOG.T3B1.md b/core/CHANGELOG.T3B1.md index c51d08a610..50b64943b0 100644 --- a/core/CHANGELOG.T3B1.md +++ b/core/CHANGELOG.T3B1.md @@ -4,6 +4,21 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [2.8.10] (21st May 2025) + +### Added +- Upgrade bundled bootloader to 2.1.10. +- Add Nostr support (in debug mode only!). [#4160] +- Solana: rent fee calculation [#4933] +- Solana: loadable token definitions [#3541] + +### Fixed +- Replaced "next page" icon with "..." ellipsis when confirming long message. [#4623] +- Fixed Solana staking dialog title. [#4787] +- Updated EIP-1559 fee-related labels. [#4819] +- Allow firmware upgrade even if language change failed. [#4827] +- Solana: fees calculation is now exact [#4965] + ## [2.8.9] (19th March 2025) ### Added @@ -1024,6 +1039,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). [#4142]: https://github.com/trezor/trezor-firmware/pull/4142 [#4151]: https://github.com/trezor/trezor-firmware/pull/4151 [#4155]: https://github.com/trezor/trezor-firmware/pull/4155 +[#4160]: https://github.com/trezor/trezor-firmware/pull/4160 [#4161]: https://github.com/trezor/trezor-firmware/pull/4161 [#4165]: https://github.com/trezor/trezor-firmware/pull/4165 [#4167]: https://github.com/trezor/trezor-firmware/pull/4167 @@ -1048,4 +1064,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). [#4541]: https://github.com/trezor/trezor-firmware/pull/4541 [#4560]: https://github.com/trezor/trezor-firmware/pull/4560 [#4571]: https://github.com/trezor/trezor-firmware/pull/4571 -[#1658739]: https://github.com/trezor/trezor-firmware/pull/1658739 +[#4623]: https://github.com/trezor/trezor-firmware/pull/4623 +[#4665]: https://github.com/trezor/trezor-firmware/pull/4665 +[#4771]: https://github.com/trezor/trezor-firmware/pull/4771 +[#4786]: https://github.com/trezor/trezor-firmware/pull/4786 +[#4787]: https://github.com/trezor/trezor-firmware/pull/4787 +[#4819]: https://github.com/trezor/trezor-firmware/pull/4819 +[#4827]: https://github.com/trezor/trezor-firmware/pull/4827 +[#4964]: https://github.com/trezor/trezor-firmware/pull/4964 diff --git a/core/CHANGELOG.T3T1.md b/core/CHANGELOG.T3T1.md index a9321a01b9..0a13467c30 100644 --- a/core/CHANGELOG.T3T1.md +++ b/core/CHANGELOG.T3T1.md @@ -4,6 +4,20 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [2.8.10] (21st May 2025) + +### Added +- Add Nostr support (in debug mode only!). [#4160] +- Visual cues to distinguish unlocked state on Homescreen. [#4964] +- Solana: rent fee calculation [#4933] +- Solana: loadable token definitions [#3541] + +### Fixed +- Replaced "next page" icon with "..." ellipsis when confirming long message. [#4623] +- Updated EIP-1559 fee-related labels. [#4819] +- Allow firmware upgrade even if language change failed. [#4827] +- Solana: fees calculation is now exact [#4965] + ## [2.8.9] (19th March 2025) ### Added @@ -1068,6 +1082,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). [#4142]: https://github.com/trezor/trezor-firmware/pull/4142 [#4151]: https://github.com/trezor/trezor-firmware/pull/4151 [#4155]: https://github.com/trezor/trezor-firmware/pull/4155 +[#4160]: https://github.com/trezor/trezor-firmware/pull/4160 [#4161]: https://github.com/trezor/trezor-firmware/pull/4161 [#4165]: https://github.com/trezor/trezor-firmware/pull/4165 [#4167]: https://github.com/trezor/trezor-firmware/pull/4167 @@ -1092,4 +1107,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). [#4541]: https://github.com/trezor/trezor-firmware/pull/4541 [#4560]: https://github.com/trezor/trezor-firmware/pull/4560 [#4571]: https://github.com/trezor/trezor-firmware/pull/4571 +[#4623]: https://github.com/trezor/trezor-firmware/pull/4623 [#4665]: https://github.com/trezor/trezor-firmware/pull/4665 +[#4771]: https://github.com/trezor/trezor-firmware/pull/4771 +[#4786]: https://github.com/trezor/trezor-firmware/pull/4786 +[#4787]: https://github.com/trezor/trezor-firmware/pull/4787 +[#4819]: https://github.com/trezor/trezor-firmware/pull/4819 +[#4827]: https://github.com/trezor/trezor-firmware/pull/4827 +[#4964]: https://github.com/trezor/trezor-firmware/pull/4964 diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index bbd90cf286..e3f36ddb5b 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -4,6 +4,24 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [2.8.10] (21st May 2025) + +### Added +- [T3B1] Upgrade bundled bootloader to 2.1.10. +- Add Nostr support (in debug mode only!). [#4160] +- [T3T1] Visual cues to distinguish unlocked state on Homescreen. [#4964] +- Solana: rent fee calculation [#4933] +- Solana: loadable token definitions [#3541] + +### Fixed +- Replaced "next page" icon with "..." ellipsis when confirming long message. [#4623] +- [T2T1] Fixed upgrade confirmation text overflow. [#4771] +- [T2T1] Fixed Solana staking dialog fonts. [#4786] +- [T2B1,T3B1] Fixed Solana staking dialog title. [#4787] +- Updated EIP-1559 fee-related labels. [#4819] +- Allow firmware upgrade even if language change failed. [#4827] +- Solana: fees calculation is now exact [#4965] + ## [2.8.9] (19th March 2025) ### Added @@ -1097,6 +1115,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). [#4142]: https://github.com/trezor/trezor-firmware/pull/4142 [#4151]: https://github.com/trezor/trezor-firmware/pull/4151 [#4155]: https://github.com/trezor/trezor-firmware/pull/4155 +[#4160]: https://github.com/trezor/trezor-firmware/pull/4160 [#4161]: https://github.com/trezor/trezor-firmware/pull/4161 [#4165]: https://github.com/trezor/trezor-firmware/pull/4165 [#4167]: https://github.com/trezor/trezor-firmware/pull/4167 @@ -1121,4 +1140,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). [#4541]: https://github.com/trezor/trezor-firmware/pull/4541 [#4560]: https://github.com/trezor/trezor-firmware/pull/4560 [#4571]: https://github.com/trezor/trezor-firmware/pull/4571 +[#4623]: https://github.com/trezor/trezor-firmware/pull/4623 [#4665]: https://github.com/trezor/trezor-firmware/pull/4665 +[#4771]: https://github.com/trezor/trezor-firmware/pull/4771 +[#4786]: https://github.com/trezor/trezor-firmware/pull/4786 +[#4787]: https://github.com/trezor/trezor-firmware/pull/4787 +[#4819]: https://github.com/trezor/trezor-firmware/pull/4819 +[#4827]: https://github.com/trezor/trezor-firmware/pull/4827 +[#4964]: https://github.com/trezor/trezor-firmware/pull/4964 diff --git a/core/embed/models/T3B1/bootloaders/bootloader_T3B1.bin b/core/embed/models/T3B1/bootloaders/bootloader_T3B1.bin index a7bb956a54..9560d1f50a 100644 Binary files a/core/embed/models/T3B1/bootloaders/bootloader_T3B1.bin and b/core/embed/models/T3B1/bootloaders/bootloader_T3B1.bin differ diff --git a/core/embed/models/T3B1/bootloaders/bootloader_hashes.h b/core/embed/models/T3B1/bootloaders/bootloader_hashes.h index 2cf13e074e..c46568040b 100644 --- a/core/embed/models/T3B1/bootloaders/bootloader_hashes.h +++ b/core/embed/models/T3B1/bootloaders/bootloader_hashes.h @@ -4,9 +4,9 @@ // Auto-generated file, do not edit. // clang-format off -// bootloader_T3B1.bin version 2.1.8.0 -#define BOOTLOADER_T3B1_00 {0x23, 0x64, 0x01, 0x0c, 0x96, 0xc1, 0x04, 0x2f, 0x54, 0x12, 0x53, 0xb5, 0xd7, 0x23, 0xcf, 0xf9, 0x18, 0x59, 0xf1, 0xdd, 0x6a, 0x5e, 0x3a, 0x3f, 0xf2, 0xf1, 0x71, 0x55, 0xaf, 0x2e, 0x48, 0x92} -#define BOOTLOADER_T3B1_FF {0x8f, 0x63, 0x1a, 0x98, 0x56, 0x9c, 0xcc, 0xf1, 0xfc, 0x0b, 0x98, 0x62, 0x5d, 0xc6, 0xc7, 0x33, 0x73, 0x90, 0x2f, 0x69, 0x02, 0x57, 0xbd, 0x5e, 0x31, 0x4c, 0x0b, 0x5a, 0xdb, 0x01, 0x17, 0x24} +// bootloader_T3B1.bin version 2.1.10.0 +#define BOOTLOADER_T3B1_00 {0x64, 0x7c, 0xac, 0x56, 0x1d, 0x10, 0xcb, 0x55, 0x78, 0x01, 0xce, 0x54, 0x85, 0xa0, 0xe7, 0x39, 0x08, 0x6f, 0xb9, 0xc2, 0x87, 0x35, 0x8b, 0x75, 0xa4, 0x7d, 0xdd, 0x7a, 0xd5, 0x10, 0xa7, 0x1f} +#define BOOTLOADER_T3B1_FF {0x49, 0xdd, 0x94, 0x60, 0xb7, 0xe9, 0x57, 0x6e, 0x7d, 0xb6, 0xd7, 0x63, 0x47, 0x04, 0xb4, 0x58, 0x3d, 0x47, 0x45, 0x57, 0xf3, 0x35, 0x69, 0x05, 0x8b, 0x84, 0x24, 0xdc, 0x81, 0x88, 0x80, 0x98} // bootloader_T3B1_qa.bin version 2.1.7.0 #define BOOTLOADER_T3B1_QA_00 {0x2e, 0x90, 0x8a, 0x99, 0x25, 0x93, 0xcd, 0x9c, 0xf1, 0x23, 0x1e, 0x4e, 0x41, 0xfc, 0xc9, 0xf1, 0x4b, 0x06, 0x69, 0x57, 0x6e, 0x64, 0x84, 0x1c, 0xb1, 0xd9, 0x89, 0x0c, 0xa5, 0xb4, 0x38, 0xeb} diff --git a/core/src/apps/common/definitions_constants.py b/core/src/apps/common/definitions_constants.py index b220040a15..62dac5ecfc 100644 --- a/core/src/apps/common/definitions_constants.py +++ b/core/src/apps/common/definitions_constants.py @@ -9,7 +9,7 @@ PUBLIC_KEYS = ( b"\xb8\xd2\xb2\x1d\xe2\x71\x24\xf0\x51\x1f\x90\x3a\xe7\xe6\x0e\x07\x96\x18\x10\xa0\xb8\xf2\x8e\xa7\x55\xfa\x50\x36\x7a\x8a\x2b\x8b", ) -MIN_DATA_VERSION = 1738953548 +MIN_DATA_VERSION = 1741090563 FORMAT_VERSION = b"trzd1" if __debug__: diff --git a/core/translations/signatures.json b/core/translations/signatures.json index 614134176e..cda2fe2c81 100644 --- a/core/translations/signatures.json +++ b/core/translations/signatures.json @@ -5,6 +5,13 @@ "commit": "be096b28adbe7c354dd502167c52e09be81140e2" }, "history": [ + { + "signature": "0309f4f95fa152310e8a984e3b105cd899d12e37a7510057f37f20a72955635e0ff1605da8c44a847c86f8b0aa0afada995f0c628234fa910d0aa275fbaef8f504", + "version": "2.8.10.0", + "merkle_root": "cf835159e227117eb1c2cd8a784c259b523c5b9489e408a4cefa169601437af6", + "datetime": "2025-05-12T07:36:20.997218", + "commit": "2a65d18200580005dc419b9569ed97fae440806a" + }, { "signature": "03a0f2df5f468356b0444a24050a60789bff459a90328533b0aa9693666ca3145c8df72adc23f5b7a52d0814ef58c44ebec0b4f4482d12fa137b6c9a8858374209", "version": "2.8.9.0", diff --git a/legacy/firmware/.changelog.d/4851.added b/legacy/firmware/.changelog.d/4851.added deleted file mode 100644 index c5ae5d78c1..0000000000 --- a/legacy/firmware/.changelog.d/4851.added +++ /dev/null @@ -1 +0,0 @@ -Clear sign ETH staking transactions on Everstake pool. diff --git a/legacy/firmware/.changelog.d/4932.fixed b/legacy/firmware/.changelog.d/4932.fixed deleted file mode 100644 index 7710c9923e..0000000000 --- a/legacy/firmware/.changelog.d/4932.fixed +++ /dev/null @@ -1 +0,0 @@ -Use `GWei` when formatting large ETH amounts. diff --git a/legacy/firmware/CHANGELOG.md b/legacy/firmware/CHANGELOG.md index 54b5b23c11..5aec73c64c 100644 --- a/legacy/firmware/CHANGELOG.md +++ b/legacy/firmware/CHANGELOG.md @@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## 1.13.1 [21st May 2025] + +### Added +- Clear sign ETH staking transactions on Everstake pool. [#4851] +- Entropy check workflow in ResetDevice. + +### Fixed +- Use `GWei` when formatting large ETH amounts. [#4932] + ## 1.13.0 [19th February 2025] ### Added @@ -640,3 +649,5 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). [#4119]: https://github.com/trezor/trezor-firmware/pull/4119 [#4324]: https://github.com/trezor/trezor-firmware/pull/4324 [#4396]: https://github.com/trezor/trezor-firmware/pull/4396 +[#4851]: https://github.com/trezor/trezor-firmware/pull/4851 +[#4932]: https://github.com/trezor/trezor-firmware/pull/4932 diff --git a/legacy/firmware/fsm.c b/legacy/firmware/fsm.c index 7658111ecb..eb4392a70e 100644 --- a/legacy/firmware/fsm.c +++ b/legacy/firmware/fsm.c @@ -229,20 +229,33 @@ static const CoinInfo *fsm_getCoin(bool has_name, const char *name) { return coin; } -static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, - size_t address_n_count, - uint32_t *fingerprint) { +static HDNode *fsm_getDerivedNodeEx(const char *curve, + const uint32_t *address_n, + size_t address_n_count, const uint8_t *seed, + uint32_t *fingerprint) { static CONFIDENTIAL HDNode node; if (fingerprint) { *fingerprint = 0; } - if (!config_getRootNode(&node, curve)) { - layoutHome(); - return 0; + + if (seed == NULL) { + if (!config_getRootNode(&node, curve)) { + layoutHome(); + return 0; + } + } else { + if (hdnode_from_seed(seed, 64, curve, &node) != 1) { + fsm_sendFailure(FailureType_Failure_NotInitialized, + _("Unsupported curve")); + layoutHome(); + return 0; + } } + if (!address_n || address_n_count == 0) { return &node; } + if (hdnode_private_ckd_cached(&node, address_n, address_n_count, fingerprint) == 0) { fsm_sendFailure(FailureType_Failure_ProcessError, @@ -253,6 +266,13 @@ static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, return &node; } +static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, + size_t address_n_count, + uint32_t *fingerprint) { + return fsm_getDerivedNodeEx(curve, address_n, address_n_count, NULL, + fingerprint); +} + static bool fsm_getSlip21Key(const char *path[], size_t path_count, uint8_t key[32]) { const uint8_t *seed = config_getSeed(); @@ -413,6 +433,7 @@ void fsm_msgRebootToBootloader(void) { } void fsm_abortWorkflows(void) { + reset_abort(); recovery_abort(); signing_abort(); authorization_type = 0; diff --git a/legacy/firmware/fsm.h b/legacy/firmware/fsm.h index 37d2183c02..abce2e9ec2 100644 --- a/legacy/firmware/fsm.h +++ b/legacy/firmware/fsm.h @@ -64,6 +64,7 @@ void fsm_msgLoadDevice(const LoadDevice *msg); #endif void fsm_msgResetDevice(const ResetDevice *msg); void fsm_msgEntropyAck(const EntropyAck *msg); +void fsm_msgEntropyCheckContinue(const EntropyCheckContinue *msg); void fsm_msgBackupDevice(const BackupDevice *msg); void fsm_msgCancel(const Cancel *msg); void fsm_msgLockDevice(const LockDevice *msg); diff --git a/legacy/firmware/fsm_msg_coin.h b/legacy/firmware/fsm_msg_coin.h index 66ae313f48..1ceab3b14b 100644 --- a/legacy/firmware/fsm_msg_coin.h +++ b/legacy/firmware/fsm_msg_coin.h @@ -20,10 +20,15 @@ void fsm_msgGetPublicKey(const GetPublicKey *msg) { RESP_INIT(PublicKey); - CHECK_INITIALIZED - CHECK_PIN + // Get temporary seed if running entropy check, otherwise ensure the device is + // initialized. + const uint8_t *seed = reset_get_seed(); + if (seed == NULL) { + CHECK_INITIALIZED + } + InputScriptType script_type = msg->has_script_type ? msg->script_type : InputScriptType_SPENDADDRESS; @@ -50,15 +55,23 @@ void fsm_msgGetPublicKey(const GetPublicKey *msg) { } } + // Make sure we never display the temporary XPUB to the user. + if (seed != NULL && msg->show_display) { + fsm_sendFailure(FailureType_Failure_DataError, + _("Showing temporary XPUB is forbidden")); + layoutHome(); + return; + } + // derive m/0' to obtain root_fingerprint uint32_t root_fingerprint; uint32_t path[1] = {PATH_HARDENED | 0}; - HDNode *node = fsm_getDerivedNode(curve, path, 1, &root_fingerprint); + HDNode *node = fsm_getDerivedNodeEx(curve, path, 1, seed, &root_fingerprint); if (!node) return; uint32_t fingerprint; - node = fsm_getDerivedNode(curve, msg->address_n, msg->address_n_count, - &fingerprint); + node = fsm_getDerivedNodeEx(curve, msg->address_n, msg->address_n_count, seed, + &fingerprint); if (!node) return; if (hdnode_fill_public_key(node) != 0) { @@ -132,7 +145,11 @@ void fsm_msgGetPublicKey(const GetPublicKey *msg) { resp->root_fingerprint = root_fingerprint; msg_write(MessageType_MessageType_PublicKey, resp); - layoutHome(); + + // Keep screen layout when running entropy check. + if (seed == NULL) { + layoutHome(); + } } static PathSchema fsm_getUnlockedSchema(MessageType message_type) { diff --git a/legacy/firmware/fsm_msg_common.h b/legacy/firmware/fsm_msg_common.h index ab6beb5820..849d579be4 100644 --- a/legacy/firmware/fsm_msg_common.h +++ b/legacy/firmware/fsm_msg_common.h @@ -321,6 +321,8 @@ void fsm_msgResetDevice(const ResetDevice *msg) { msg->strength == 192 || msg->strength == 256, _("Invalid seed strength")); + fsm_abortWorkflows(); + reset_init(msg->has_strength ? msg->strength : 128, msg->has_passphrase_protection && msg->passphrase_protection, msg->has_pin_protection && msg->pin_protection, @@ -328,13 +330,18 @@ void fsm_msgResetDevice(const ResetDevice *msg) { msg->has_label ? msg->label : 0, msg->has_u2f_counter ? msg->u2f_counter : 0, msg->has_skip_backup ? msg->skip_backup : false, - msg->has_no_backup ? msg->no_backup : false); + msg->has_no_backup ? msg->no_backup : false, + msg->has_entropy_check ? msg->entropy_check : false); } void fsm_msgEntropyAck(const EntropyAck *msg) { reset_entropy(msg->entropy.bytes, msg->entropy.size); } +void fsm_msgEntropyCheckContinue(const EntropyCheckContinue *msg) { + reset_continue(msg->has_finish ? msg->finish : false); +} + void fsm_msgBackupDevice(const BackupDevice *msg) { (void)msg; @@ -497,6 +504,8 @@ void fsm_msgRecoveryDevice(const RecoveryDevice *msg) { msg->type == RecoveryType_DryRun, _("UnlockRepeatedBackup not supported")) + fsm_abortWorkflows(); + const bool dry_run = msg->has_type ? msg->type == RecoveryType_DryRun : false; if (!dry_run) { CHECK_NOT_INITIALIZED diff --git a/legacy/firmware/protob/Makefile b/legacy/firmware/protob/Makefile index 1c26e6d94a..a1c246ff1b 100644 --- a/legacy/firmware/protob/Makefile +++ b/legacy/firmware/protob/Makefile @@ -11,7 +11,7 @@ SKIPPED_MESSAGES := Cardano DebugMonero Eos Monero Ontology Ripple SdProtect Tez UnlockBootloader AuthenticateDevice AuthenticityProof \ Solana StellarClaimClaimableBalanceOp \ ChangeLanguage DataChunkRequest DataChunkAck \ - SetBrightness DebugLinkOptigaSetSecMax EntropyCheckReady EntropyCheckContinue \ + SetBrightness DebugLinkOptigaSetSecMax \ BenchmarkListNames BenchmarkRun BenchmarkNames BenchmarkResult \ NostrGetPubkey NostrPubkey NostrSignEvent NostrEventSignature \ BleUnpair diff --git a/legacy/firmware/protob/messages-management.options b/legacy/firmware/protob/messages-management.options index e9a2aa0954..17c5c0850b 100644 --- a/legacy/firmware/protob/messages-management.options +++ b/legacy/firmware/protob/messages-management.options @@ -30,8 +30,8 @@ BackupDevice.groups type:FT_IGNORE Entropy.entropy max_size:1024 -EntropyRequest.entropy_commitment type:FT_IGNORE -EntropyRequest.prev_entropy type:FT_IGNORE +EntropyRequest.entropy_commitment max_size:32 +EntropyRequest.prev_entropy max_size:32 EntropyAck.entropy max_size:128 diff --git a/legacy/firmware/reset.c b/legacy/firmware/reset.c index 928465f53a..dc682310a4 100644 --- a/legacy/firmware/reset.c +++ b/legacy/firmware/reset.c @@ -22,6 +22,7 @@ #include "config.h" #include "fsm.h" #include "gettext.h" +#include "hmac.h" #include "layout2.h" #include "memzero.h" #include "messages.h" @@ -34,18 +35,37 @@ static uint32_t strength; static uint8_t int_entropy[32]; -static bool awaiting_entropy = false; +static uint8_t seed[64]; +static const char *reset_mnemonic; static bool skip_backup = false; static bool no_backup = false; +static bool entropy_check = false; + +static enum { + RESET_NONE = 0, + RESET_ENTROPY_REQUEST, + RESET_ENTROPY_CHECK_READY, +} reset_state = RESET_NONE; + +static void send_entropy_request(bool set_prev_entropy); +static void reset_finish(void); + +static void entropy_check_progress(uint32_t iter, uint32_t total) { + (void)iter; + (void)total; + layoutProgress(_("Entropy check"), 0); +} void reset_init(uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, - uint32_t u2f_counter, bool _skip_backup, bool _no_backup) { + uint32_t u2f_counter, bool _skip_backup, bool _no_backup, + bool _entropy_check) { if (_strength != 128 && _strength != 192 && _strength != 256) return; strength = _strength; skip_backup = _skip_backup; no_backup = _no_backup; + entropy_check = _entropy_check; layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("create a new wallet?"), NULL, @@ -56,8 +76,6 @@ void reset_init(uint32_t _strength, bool passphrase_protection, return; } - random_buffer(int_entropy, 32); - if (pin_protection && !protectChangePin(false)) { layoutHome(); return; @@ -67,36 +85,79 @@ void reset_init(uint32_t _strength, bool passphrase_protection, config_setLanguage(language); config_setLabel(label); config_setU2FCounter(u2f_counter); + send_entropy_request(false); +} +static void send_entropy_request(bool set_prev_entropy) { EntropyRequest resp = {0}; - memzero(&resp, sizeof(EntropyRequest)); + if (set_prev_entropy) { + memcpy(resp.prev_entropy.bytes, int_entropy, sizeof(int_entropy)); + resp.prev_entropy.size = sizeof(int_entropy); + resp.has_prev_entropy = true; + } + + random_buffer(int_entropy, sizeof(int_entropy)); + if (entropy_check) { + hmac_sha256(int_entropy, sizeof(int_entropy), NULL, 0, + resp.entropy_commitment.bytes); + resp.entropy_commitment.size = SHA256_DIGEST_LENGTH; + resp.has_entropy_commitment = true; + } msg_write(MessageType_MessageType_EntropyRequest, &resp); - awaiting_entropy = true; + reset_state = RESET_ENTROPY_REQUEST; } void reset_entropy(const uint8_t *ext_entropy, uint32_t len) { - if (!awaiting_entropy) { + if (reset_state != RESET_ENTROPY_REQUEST) { fsm_sendFailure(FailureType_Failure_UnexpectedMessage, - _("Not in Reset mode")); + _("Entropy not requested")); return; } - awaiting_entropy = false; + uint8_t secret[SHA256_DIGEST_LENGTH] = {0}; SHA256_CTX ctx = {0}; sha256_Init(&ctx); SHA256_UPDATE_BYTES(&ctx, int_entropy, 32); sha256_Update(&ctx, ext_entropy, len); - sha256_Final(&ctx, int_entropy); - const char *mnemonic = mnemonic_from_data(int_entropy, strength / 8); - memzero(int_entropy, 32); + sha256_Final(&ctx, secret); + reset_mnemonic = mnemonic_from_data(secret, strength / 8); + memzero(secret, sizeof(secret)); + if (!entropy_check) { + reset_finish(); + return; + } + reset_state = RESET_ENTROPY_CHECK_READY; + mnemonic_to_seed(reset_mnemonic, "", seed, entropy_check_progress); + EntropyCheckReady resp = {0}; + msg_write(MessageType_MessageType_EntropyCheckReady, &resp); +} + +void reset_continue(bool finish) { + if (reset_state != RESET_ENTROPY_CHECK_READY) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, + _("Entropy check not ready")); + return; + } + + if (finish) { + reset_finish(); + } else { + send_entropy_request(true); + } +} + +static void reset_finish(void) { + memzero(int_entropy, sizeof(int_entropy)); + memzero(seed, sizeof(seed)); + reset_state = RESET_NONE; if (skip_backup || no_backup) { if (no_backup) { config_setNoBackup(); } else { config_setNeedsBackup(true); } - if (config_setMnemonic(mnemonic)) { + if (config_setMnemonic(reset_mnemonic)) { fsm_sendSuccess(_("Device successfully initialized")); } else { fsm_sendFailure(FailureType_Failure_ProcessError, @@ -104,11 +165,18 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) { } layoutHome(); } else { - reset_backup(false, mnemonic); + reset_backup(false, reset_mnemonic); } mnemonic_clear(); } +const uint8_t *reset_get_seed(void) { + if (reset_state != RESET_ENTROPY_CHECK_READY) { + return NULL; + } + return seed; +} + static char current_word[10]; // separated == true if called as a separate workflow via BackupMessage @@ -170,6 +238,16 @@ void reset_backup(bool separated, const char *mnemonic) { layoutHome(); } +void reset_abort(void) { + memzero(int_entropy, sizeof(int_entropy)); + memzero(seed, sizeof(seed)); + mnemonic_clear(); + if (reset_state != RESET_NONE) { + reset_state = RESET_NONE; + layoutHome(); + } +} + #if DEBUG_LINK uint32_t reset_get_int_entropy(uint8_t *entropy) { diff --git a/legacy/firmware/reset.h b/legacy/firmware/reset.h index cebf33cc23..5d0bee744c 100644 --- a/legacy/firmware/reset.h +++ b/legacy/firmware/reset.h @@ -25,10 +25,14 @@ void reset_init(uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, - uint32_t u2f_counter, bool _skip_backup, bool _no_backup); + uint32_t u2f_counter, bool _skip_backup, bool _no_backup, + bool _entropy_check); void reset_entropy(const uint8_t *ext_entropy, uint32_t len); +void reset_continue(bool finish); +const uint8_t *reset_get_seed(void); void reset_backup(bool separated, const char *mnemonic); uint32_t reset_get_int_entropy(uint8_t *entropy); const char *reset_get_word(void); +void reset_abort(void); #endif diff --git a/tests/device_tests/reset_recovery/test_reset_bip39_t1.py b/tests/device_tests/reset_recovery/test_reset_bip39_t1.py index 0c96ee4f5c..04b66054d6 100644 --- a/tests/device_tests/reset_recovery/test_reset_bip39_t1.py +++ b/tests/device_tests/reset_recovery/test_reset_bip39_t1.py @@ -14,14 +14,23 @@ # You should have received a copy of the License along with this library. # If not, see . +from typing import Generator + import pytest from mnemonic import Mnemonic +from slip10 import SLIP10 from trezorlib import device, messages +from trezorlib.btc import get_public_node from trezorlib.debuglink import TrezorClientDebugLink as Client from trezorlib.tools import parse_path -from ...common import EXTERNAL_ENTROPY, generate_entropy +from ...common import ( + EXTERNAL_ENTROPY, + MOCK_GET_ENTROPY, + BRGeneratorType, + generate_entropy, +) pytestmark = pytest.mark.models("legacy") @@ -216,3 +225,130 @@ def test_already_initialized(client: Client): pin_protection=True, label="label", ) + + +class Bip39InputFlow: + def __init__(self, client: Client): + self.client = client + self.mnemonic = None + + def _get_mnemonic( + self, strength: int + ) -> Generator[None, messages.ButtonRequest, list[str]]: + mnemonic: list[str] = [] + for _ in range(strength // 32 * 3): + br = yield + assert br.code == messages.ButtonRequestType.ConfirmWord + mnemonic.append(self.client.debug.read_reset_word()) + self.client.debug.press_yes() + return mnemonic + + def input_flow_bip39_reset_backup(self, strength: int) -> BRGeneratorType: + # 1. Confirm Reset + br = yield + assert br.code == messages.ButtonRequestType.ProtectCall + self.client.debug.press_yes() + + mnemonic_write = yield from self._get_mnemonic(strength) + mnemonic_check = yield from self._get_mnemonic(strength) + assert mnemonic_write == mnemonic_check + + self.mnemonic = " ".join(mnemonic_write) + + +@pytest.mark.setup_client(uninitialized=True) +def test_reset_entropy_check(client: Client): + strength = 256 # 24 words + + with client: + IF = Bip39InputFlow(client) + client.set_input_flow(IF.input_flow_bip39_reset_backup(strength)) + # No PIN, no passphrase + path_xpubs = device.setup( + client, + strength=strength, + passphrase_protection=False, + pin_protection=False, + label="test", + entropy_check_count=2, + backup_type=messages.BackupType.Bip39, + _get_entropy=MOCK_GET_ENTROPY, + ) + + # Check that the displayed mnemonic is identical to the stored one. + assert IF.mnemonic.encode("utf-8") == client.debug.state().mnemonic_secret + + # Check that the device is properly initialized. + assert client.features.initialized is True + assert ( + client.features.backup_availability == messages.BackupAvailability.NotAvailable + ) + assert client.features.pin_protection is False + assert client.features.passphrase_protection is False + + seed = Mnemonic.to_seed(IF.mnemonic, passphrase="") + slip10 = SLIP10.from_seed(seed) + for path, xpub in path_xpubs: + # Check that the device returns the same XPUBs as those from the entropy check. + res = get_public_node(client, path) + assert res.xpub == xpub + # Check that the XPUBs derived from the displayed mnemonic are the same as those + # from the entropy check. + assert slip10.get_xpub_from_path(path) == xpub + + +@pytest.mark.setup_client(uninitialized=True) +def test_entropy_check(client: Client): + with client: + client.set_expected_responses( + [ + messages.ButtonRequest(code=messages.ButtonRequestType.ProtectCall), + messages.EntropyRequest, + messages.EntropyCheckReady, + messages.PublicKey, + messages.PublicKey, + messages.EntropyRequest, + messages.EntropyCheckReady, + messages.PublicKey, + messages.PublicKey, + messages.EntropyRequest, + messages.EntropyCheckReady, + messages.PublicKey, + messages.PublicKey, + messages.Success, + messages.Features, + ] + ) + device.setup( + client, + strength=256, + entropy_check_count=2, + backup_type=messages.BackupType.Bip39, + skip_backup=True, + pin_protection=False, + passphrase_protection=False, + _get_entropy=MOCK_GET_ENTROPY, + ) + + +@pytest.mark.setup_client(uninitialized=True) +def test_no_entropy_check(client: Client): + with client: + client.set_expected_responses( + [ + messages.ButtonRequest(code=messages.ButtonRequestType.ProtectCall), + messages.EntropyRequest, + messages.Success, + messages.Features, + ] + ) + device.setup( + client, + strength=256, + entropy_check_count=0, + backup_type=messages.BackupType.Bip39, + skip_backup=True, + pin_protection=False, + passphrase_protection=False, + _get_entropy=MOCK_GET_ENTROPY, + ) diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json index d3c3c200c0..cc1d4b37de 100644 --- a/tests/ui_tests/fixtures.json +++ b/tests/ui_tests/fixtures.json @@ -602,10 +602,13 @@ "T1B1_en_reset_recovery-test_reset_bip39_skipbackup.py::test_reset_device_skip_backup": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "T1B1_en_reset_recovery-test_reset_bip39_skipbackup.py::test_reset_device_skip_backup_break": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "T1B1_en_reset_recovery-test_reset_bip39_t1.py::test_already_initialized": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", +"T1B1_en_reset_recovery-test_reset_bip39_t1.py::test_entropy_check": "b63a40ea5f6d8c59a2b54db8f5f01d0aaa4b0dea7c91ddd1bd40489720ae729c", "T1B1_en_reset_recovery-test_reset_bip39_t1.py::test_failed_pin": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", +"T1B1_en_reset_recovery-test_reset_bip39_t1.py::test_no_entropy_check": "b63a40ea5f6d8c59a2b54db8f5f01d0aaa4b0dea7c91ddd1bd40489720ae729c", "T1B1_en_reset_recovery-test_reset_bip39_t1.py::test_reset_device_128": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "T1B1_en_reset_recovery-test_reset_bip39_t1.py::test_reset_device_192": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "T1B1_en_reset_recovery-test_reset_bip39_t1.py::test_reset_device_256_pin": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", +"T1B1_en_reset_recovery-test_reset_bip39_t1.py::test_reset_entropy_check": "d18e5ebf3a318a04935cbf1c1d2a9591ad209d352baed8d93aa4398b87c0bc72", "T1B1_en_stellar-test_stellar.py::test_get_address[parameters0-result0]": "b004cb1a815072ae3ba9f4aadeeb9d37d3309513e973f7ddeb2ee23a056db726", "T1B1_en_stellar-test_stellar.py::test_get_address[parameters1-result1]": "101692e06782269486e3f1093fdf03200e0cdce4b4ffc7cc5fc779b80f69d1fc", "T1B1_en_stellar-test_stellar.py::test_get_address[parameters2-result2]": "508bbd5285d2f3087fa3b872ff053a286630b80beacd0b8b30c8577aa5396c86", @@ -709,7 +712,7 @@ "T1B1_en_test_msg_loaddevice.py::test_load_device_2": "f89f8fcecf250b76dcca3e52a5a678e14ca5eeae105fa59848db41ab514d6614", "T1B1_en_test_msg_loaddevice.py::test_load_device_utf": "9523984b9cd124422558fe14ae20aab35338f86f08756d11919db7b2d3b86781", "T1B1_en_test_msg_ping.py::test_ping": "de7fc40b2f35e82fa486f1b97ee3e34a96d0a67412537e8a0fddacc0b0b1649d", -"T1B1_en_test_msg_wipedevice.py::test_autolock_not_retained": "7f5d22cc7797ce4ca6d9f46f633918aba527972c8d683493e95da45503486f61", +"T1B1_en_test_msg_wipedevice.py::test_autolock_not_retained": "9ab4e01aaf78d4ffeaadf43883258fd2ded7d4f7ebbdba9c70bd60baad314860", "T1B1_en_test_msg_wipedevice.py::test_wipe_device": "aac15a6d12d21966c77572aeebd56ebc2a47ecba3a508f5a421af2a5da2919e7", "T1B1_en_test_pin.py::test_correct_pin": "31e4ef1ef1f40b58c66bcde7631fe12699321dcdfc144381ac2b3e5668d0de5c", "T1B1_en_test_pin.py::test_exponential_backoff_t1": "427faf2049e9998229e0d40c9b54f2e359a7d2df2ba129187dafc7d2f2cc9986",