What changed, and why it matters
This commit adds a key-rotation feature for the 'Evolu' / 'Suite Sync' delegated identity key used by Trezor. It introduces a rotation index that is mixed into the key derivation, lets users rotate the key on demand, and stores the current index in device storage. The change is a feature addition rather than a fix for an obvious vulnerability, but it touches sensitive key-derivation code and adds new protocol messages.
Review the key-derivation change for correctness: ensure the backwards-compatible HMAC diversifier (5 bytes for index 0, 7 bytes otherwise) cannot produce collisions between old and rotated keys. Verify that `EvoluIndexManagement` cannot be abused to downgrade or reset the rotation index, and that the `rotate` and `rotation_index` mutual-exclusion check is enforced in all code paths. Confirm that the new storage field is properly protected and that the THP credential validation path still requires a valid credential before returning any delegated key.
Security signals we found
Changes to hardware-backed key derivation (secret_keys)
Adds new wire messages for key rotation and index management
Adds device-storage field for rotation index
Adds user confirmation prompt before key rotation
Restricts sign_registration_request to Optiga-enabled builds
Renames user-facing strings from secure_sync to suite_sync
Evidence from the diff
The patch extends the Evolu/Suite Sync subsystem with key rotation. It adds rotation_index and rotate fields to protobuf messages, stores a _DELEGATED_IDENTITY_KEY_ROTATION_INDEX in device storage, and threads the index through secret_key_delegated_identity, secret_key_derive_nist256p1, and secret_key_derive_sym. A new EvoluIndexManagement message allows setting/reading the index. The get_delegated_identity_key.py workflow enforces on-device confirmation before rotation and rejects requesting a specific index while rotating. The node_rotation_index for EvoluGetNode is intentionally not tied to the stored delegated-identity index because it is passphrase-dependent. The sign_registration_request.py module is now excluded from non-Optiga builds.
Changed components
core/embed/sec/secret_keyscore/src/apps/evolucore/src/storage/device.pycommon/protob/messages-evolu.protopython/src/trezorlib/evolu.pycore/embed/sys/smcall and syscall dispatch/verifiers/stubsInspect captured patch +1890 / −265
diff --git a/common/protob/messages-evolu.proto b/common/protob/messages-evolu.proto
index 74e7c67d..cdb08bc8 100644
--- a/common/protob/messages-evolu.proto
+++ b/common/protob/messages-evolu.proto
@@ -18,6 +18,7 @@ option (include_in_bitcoin_only) = true;
*/
message EvoluGetNode {
required bytes proof_of_delegated_identity = 1;
+ optional uint32 node_rotation_index = 2 [default = 0];
}
/**
@@ -58,7 +59,9 @@ message EvoluRegistrationRequest {
*/
message EvoluGetDelegatedIdentityKey {
optional bytes thp_credential = 1; // THP credential so that we can display the host on the device
- reserved 2; // host_static_public_key is deprecated, the key stored in the channel cache is used instead
+ reserved 2; // host_static_public_key is deprecated, the key stored in the channel cache is used instead
+ optional uint32 rotation_index = 3; // The required rotation index of the delegated identity key
+ optional bool rotate = 4; // If true, rotate the delegated identity key and return it
}
/**
@@ -66,5 +69,24 @@ message EvoluGetDelegatedIdentityKey {
* @end
*/
message EvoluDelegatedIdentityKey {
- required bytes private_key = 1; // nist256p1 private key
+ required bytes private_key = 1; // nist256p1 private key
+ optional uint32 rotation_index = 2; // rotation index of the returned key
+}
+
+/**
+ * Request: Set or get the delegated identity key rotation index.
+ * @start
+ * @next EvoluIndexManagementResponse
+ * @next Failure
+ */
+message EvoluIndexManagement {
+ optional uint32 rotation_index = 1; // If the rotation index is not set, set it to this value
+}
+
+/**
+ * Response: The current delegated identity key rotation index.
+ * @end
+ */
+message EvoluIndexManagementResponse {
+ optional uint32 rotation_index = 1; // The current rotation index
}
diff --git a/common/protob/messages.proto b/common/protob/messages.proto
index c422388b..68f0f679 100644
--- a/common/protob/messages.proto
+++ b/common/protob/messages.proto
@@ -355,6 +355,8 @@ enum MessageType {
MessageType_EvoluRegistrationRequest = 2103 [(bitcoin_only) = true, (wire_out) = true];
MessageType_EvoluGetDelegatedIdentityKey = 2104 [(bitcoin_only) = true, (wire_in) = true];
MessageType_EvoluDelegatedIdentityKey = 2105 [(bitcoin_only) = true, (wire_out) = true];
+ MessageType_EvoluIndexManagement = 2106 [(bitcoin_only) = true, (wire_in) = true];
+ MessageType_EvoluIndexManagementResponse = 2107 [(bitcoin_only) = true, (wire_out) = true];
// Tron
MessageType_TronGetAddress = 2200 [(wire_in) = true];
diff --git a/core/SConscript.firmware b/core/SConscript.firmware
index c15246ca..3aaa78f6 100644
--- a/core/SConscript.firmware
+++ b/core/SConscript.firmware
@@ -773,7 +773,11 @@ if FROZEN:
])
)
- SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/evolu/*.py'))
+ SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/evolu/*.py',
+ exclude=[
+ SOURCE_PY_DIR + 'apps/evolu/sign_registration_request.py'
+ ] if not ('optiga' in FEATURES_AVAILABLE) else [])
+ ) # TODO: refactor to `OPTIGA` after rebase
if BENCHMARK:
SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/benchmark/*.py'))
diff --git a/core/SConscript.unix b/core/SConscript.unix
index e710153e..a0e6c399 100644
--- a/core/SConscript.unix
+++ b/core/SConscript.unix
@@ -788,7 +788,11 @@ if FROZEN:
])
)
- SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/evolu/*.py'))
+ SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/evolu/*.py',
+ exclude=[
+ SOURCE_PY_DIR + 'apps/evolu/sign_registration_request.py',
+ ] if "optiga" not in FEATURES_AVAILABLE else [])
+ )
if BENCHMARK:
SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/benchmark/*.py'))
diff --git a/core/embed/rust/librust_qstr.h b/core/embed/rust/librust_qstr.h
index 831f5616..b99827c5 100644
--- a/core/embed/rust/librust_qstr.h
+++ b/core/embed/rust/librust_qstr.h
@@ -768,9 +768,6 @@ static void _librust_qstrs(void) {
MP_QSTR_sd_card__use_different_card;
MP_QSTR_sd_card__wanna_format;
MP_QSTR_sd_card__wrong_sd_card;
- MP_QSTR_secure_sync__delegated_identity_key_no_thp;
- MP_QSTR_secure_sync__delegated_identity_key_thp;
- MP_QSTR_secure_sync__header;
MP_QSTR_select_menu;
MP_QSTR_select_word;
MP_QSTR_select_word_count;
@@ -850,6 +847,10 @@ static void _librust_qstrs(void) {
MP_QSTR_storage_msg__wrong_pin;
MP_QSTR_subtext;
MP_QSTR_subtitle;
+ MP_QSTR_suite_sync__delegated_identity_key_no_thp;
+ MP_QSTR_suite_sync__delegated_identity_key_thp;
+ MP_QSTR_suite_sync__header;
+ MP_QSTR_suite_sync__rotate_key;
MP_QSTR_switch_off;
MP_QSTR_text;
MP_QSTR_text_check;
diff --git a/core/embed/rust/src/translations/generated/translated_string.rs b/core/embed/rust/src/translations/generated/translated_string.rs
index 68dc2133..7452933b 100644
--- a/core/embed/rust/src/translations/generated/translated_string.rs
+++ b/core/embed/rust/src/translations/generated/translated_string.rs
@@ -1555,9 +1555,9 @@ pub enum TranslatedString {
#[cfg(feature = "universal_fw")]
ripple__destination_tag_missing = 1168, // "Destination tag is not set. Typically needed when sending to exchanges."
words__comm_trouble = 1169, // "Your Trezor is having trouble communicating with your connected device."
- secure_sync__delegated_identity_key_no_thp = 1170, // "Allow Trezor Suite to use Suite Sync with this Trezor?"
- secure_sync__delegated_identity_key_thp = 1171, // "Allow {0} on {1} to use Suite Sync with this Trezor?"
- secure_sync__header = 1173, // "Suite Sync"
+ suite_sync__delegated_identity_key_no_thp = 1170, // "Allow Trezor Suite to use Suite Sync with this Trezor?"
+ suite_sync__delegated_identity_key_thp = 1171, // "Allow {0} on {1} to use Suite Sync with this Trezor?"
+ suite_sync__header = 1173, // "Suite Sync"
words__note = 1174, // "Note"
words__fee_limit = 1175, // "Fee limit"
#[cfg(feature = "universal_fw")]
@@ -1572,6 +1572,7 @@ pub enum TranslatedString {
#[cfg(feature = "universal_fw")]
ethereum__confirm_contract = 1183, // "Confirm contract"
words__intent = 1184, // "Intent"
+ suite_sync__rotate_key = 1185, // "You are about to rotate the delegated identity key used for Suite Sync. This will invalidate previous keys. Do you want to proceed?"
}
impl TranslatedString {
@@ -2764,6 +2765,7 @@ impl TranslatedString {
"Voting",
"Confirm contract",
"Intent",
+ "You are about to rotate the delegated identity key used for Suite Sync. This will invalidate previous keys. Do you want to proceed?",
);
#[cfg(all(feature = "debug", feature = "universal_fw"))]
@@ -3954,6 +3956,7 @@ impl TranslatedString {
21439,
21455,
21461,
+ 21592,
];
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -5143,6 +5146,7 @@ impl TranslatedString {
"Voting",
"Confirm contract",
"Intent",
+ "You are about to rotate the delegated identity key used for Suite Sync. This will invalidate previous keys. Do you want to proceed?",
);
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -6333,6 +6337,7 @@ impl TranslatedString {
21439,
21455,
21461,
+ 21592,
];
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -7522,6 +7527,7 @@ impl TranslatedString {
"Voting",
"Confirm contract",
"Intent",
+ "You are about to rotate the delegated identity key used for Suite Sync. This will invalidate previous keys. Do you want to proceed?",
);
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -8712,6 +8718,7 @@ impl TranslatedString {
21439,
21455,
21461,
+ 21592,
];
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -9901,6 +9908,7 @@ impl TranslatedString {
"Voting",
"Confirm contract",
"Intent",
+ "You are about to rotate the delegated identity key used for Suite Sync. This will invalidate previous keys. Do you want to proceed?",
);
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -11091,6 +11099,7 @@ impl TranslatedString {
21439,
21455,
21461,
+ 21592,
];
} else if #[cfg(feature = "layout_caesar")] {
@@ -12281,6 +12290,7 @@ impl TranslatedString {
"Voting",
"Confirm contract",
"Intent",
+ "You are about to rotate the delegated identity key used for Suite Sync. This will invalidate previous keys. Do you want to proceed?",
);
#[cfg(all(feature = "debug", feature = "universal_fw"))]
@@ -13471,6 +13481,7 @@ impl TranslatedString {
18667,
18683,
18689,
+ 18820,
];
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -14660,6 +14671,7 @@ impl TranslatedString {
"Voting",
"Confirm contract",
"Intent",
+ "You are about to rotate the delegated identity key used for Suite Sync. This will invalidate previous keys. Do you want to proceed?",
);
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -15850,6 +15862,7 @@ impl TranslatedString {
18667,
18683,
18689,
+ 18820,
];
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -17039,6 +17052,7 @@ impl TranslatedString {
"Voting",
"Confirm contract",
"Intent",
+ "You are about to rotate the delegated identity key used for Suite Sync. This will invalidate previous keys. Do you want to proceed?",
);
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -18229,6 +18243,7 @@ impl TranslatedString {
18667,
18683,
18689,
+ 18820,
];
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -19418,6 +19433,7 @@ impl TranslatedString {
"Voting",
"Confirm contract",
"Intent",
+ "You are about to rotate the delegated identity key used for Suite Sync. This will invalidate previous keys. Do you want to proceed?",
);
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -20608,6 +20624,7 @@ impl TranslatedString {
18667,
18683,
18689,
+ 18820,
];
} else if #[cfg(feature = "layout_delizia")] {
@@ -21798,6 +21815,7 @@ impl TranslatedString {
"Voting",
"Confirm contract",
"Intent",
+ "You are about to rotate the delegated identity key used for Suite Sync. This will invalidate previous keys. Do you want to proceed?",
);
#[cfg(all(feature = "debug", feature = "universal_fw"))]
@@ -22988,6 +23006,7 @@ impl TranslatedString {
20523,
20539,
20545,
+ 20676,
];
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -24177,6 +24196,7 @@ impl TranslatedString {
"Voting",
"Confirm contract",
"Intent",
+ "You are about to rotate the delegated identity key used for Suite Sync. This will invalidate previous keys. Do you want to proceed?",
);
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -25367,6 +25387,7 @@ impl TranslatedString {
20523,
20539,
20545,
+ 20676,
];
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -26556,6 +26577,7 @@ impl TranslatedString {
"Voting",
"Confirm contract",
"Intent",
+ "You are about to rotate the delegated identity key used for Suite Sync. This will invalidate previous keys. Do you want to proceed?",
);
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -27746,6 +27768,7 @@ impl TranslatedString {
20523,
20539,
20545,
+ 20676,
];
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -28935,6 +28958,7 @@ impl TranslatedString {
"Voting",
"Confirm contract",
"Intent",
+ "You are about to rotate the delegated identity key used for Suite Sync. This will invalidate previous keys. Do you want to proceed?",
);
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -30125,6 +30149,7 @@ impl TranslatedString {
20523,
20539,
20545,
+ 20676,
];
} else if #[cfg(feature = "layout_eckhart")] {
@@ -31315,6 +31340,7 @@ impl TranslatedString {
"Voting",
"Confirm contract",
"Intent",
+ "You are about to rotate the delegated identity key used for Suite Sync. This will invalidate previous keys. Do you want to proceed?",
);
#[cfg(all(feature = "debug", feature = "universal_fw"))]
@@ -32505,6 +32531,7 @@ impl TranslatedString {
21232,
21248,
21254,
+ 21385,
];
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -33694,6 +33721,7 @@ impl TranslatedString {
"Voting",
"Confirm contract",
"Intent",
+ "You are about to rotate the delegated identity key used for Suite Sync. This will invalidate previous keys. Do you want to proceed?",
);
#[cfg(all(feature = "debug", not(feature = "universal_fw")))]
@@ -34884,6 +34912,7 @@ impl TranslatedString {
21232,
21248,
21254,
+ 21385,
];
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -36073,6 +36102,7 @@ impl TranslatedString {
"Voting",
"Confirm contract",
"Intent",
+ "You are about to rotate the delegated identity key used for Suite Sync. This will invalidate previous keys. Do you want to proceed?",
);
#[cfg(all(not(feature = "debug"), feature = "universal_fw"))]
@@ -37263,6 +37293,7 @@ impl TranslatedString {
21232,
21248,
21254,
+ 21385,
];
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -38452,6 +38483,7 @@ impl TranslatedString {
"Voting",
"Confirm contract",
"Intent",
+ "You are about to rotate the delegated identity key used for Suite Sync. This will invalidate previous keys. Do you want to proceed?",
);
#[cfg(all(not(feature = "debug"), not(feature = "universal_fw")))]
@@ -39642,6 +39674,7 @@ impl TranslatedString {
21232,
21248,
21254,
+ 21385,
];
}
@@ -40774,9 +40807,6 @@ impl TranslatedString {
(Qstr::MP_QSTR_sd_card__use_different_card, Self::sd_card__use_different_card),
(Qstr::MP_QSTR_sd_card__wanna_format, Self::sd_card__wanna_format),
(Qstr::MP_QSTR_sd_card__wrong_sd_card, Self::sd_card__wrong_sd_card),
- (Qstr::MP_QSTR_secure_sync__delegated_identity_key_no_thp, Self::secure_sync__delegated_identity_key_no_thp),
- (Qstr::MP_QSTR_secure_sync__delegated_identity_key_thp, Self::secure_sync__delegated_identity_key_thp),
- (Qstr::MP_QSTR_secure_sync__header, Self::secure_sync__header),
(Qstr::MP_QSTR_send__cancel_sign, Self::send__cancel_sign),
(Qstr::MP_QSTR_send__cancel_transaction, Self::send__cancel_transaction),
(Qstr::MP_QSTR_send__confirm_sending, Self::send__confirm_sending),
@@ -41005,6 +41035,10 @@ impl TranslatedString {
(Qstr::MP_QSTR_storage_msg__starting, Self::storage_msg__starting),
(Qstr::MP_QSTR_storage_msg__verifying_pin, Self::storage_msg__verifying_pin),
(Qstr::MP_QSTR_storage_msg__wrong_pin, Self::storage_msg__wrong_pin),
+ (Qstr::MP_QSTR_suite_sync__delegated_identity_key_no_thp, Self::suite_sync__delegated_identity_key_no_thp),
+ (Qstr::MP_QSTR_suite_sync__delegated_identity_key_thp, Self::suite_sync__delegated_identity_key_thp),
+ (Qstr::MP_QSTR_suite_sync__header, Self::suite_sync__header),
+ (Qstr::MP_QSTR_suite_sync__rotate_key, Self::suite_sync__rotate_key),
#[cfg(feature = "universal_fw")]
(Qstr::MP_QSTR_tezos__baker_address, Self::tezos__baker_address),
#[cfg(feature = "universal_fw")]
diff --git a/core/embed/sec/secret_keys/inc/sec/secret_keys.h b/core/embed/sec/secret_keys/inc/sec/secret_keys.h
index 83c44c33..39db5ac8 100644
--- a/core/embed/sec/secret_keys/inc/sec/secret_keys.h
+++ b/core/embed/sec/secret_keys/inc/sec/secret_keys.h
@@ -23,7 +23,8 @@
#include <ecdsa.h>
-secbool secret_key_delegated_identity(uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]);
+secbool secret_key_delegated_identity(uint16_t rotation_index,
+ uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]);
#ifdef SECURE_MODE
diff --git a/core/embed/sec/secret_keys/secret_keys_common.c b/core/embed/sec/secret_keys/secret_keys_common.c
index 0bdec212..29a5aa45 100644
--- a/core/embed/sec/secret_keys/secret_keys_common.c
+++ b/core/embed/sec/secret_keys/secret_keys_common.c
@@ -35,6 +35,7 @@
#include "secret_keys_common.h"
static void diversify_and_derive(uint16_t index, uint16_t subindex,
+ uint16_t rotation_index,
const uint8_t master_key[SHA256_DIGEST_LENGTH],
uint8_t master_key_length,
uint8_t dest[SHA256_DIGEST_LENGTH]) {
@@ -42,17 +43,30 @@ static void diversify_and_derive(uint16_t index, uint16_t subindex,
// - the key derivation index (2 bytes big-endian), which identifies the
// purpose of the key,
// - the subindex (2 bytes big-endian), which is incremented until the derived
- // key meets required criteria, and
+ // key meets required criteria,
// - the block index (1 byte), which can be used to produce outputs that are
- // longer than 32 bytes.
- uint8_t diversifier[] = {index >> 8, index & 0xff, subindex >> 8,
- subindex & 0xff, 0};
-
- hmac_sha256(master_key, master_key_length, diversifier, sizeof(diversifier),
+ // longer than 32 bytes, and
+ // - the rotation index (2 bytes), which can be used to produce a new key when
+ // the previous one is revoked.
+ // For backwards compatibility the rotation index is included in the HMAC
+ // calculation only if it is non-zero.
+
+ uint8_t diversifier[] = {(index >> 8) & 0xFF,
+ index & 0xFF,
+ (subindex >> 8) & 0xFF,
+ subindex & 0xFF,
+ 0,
+ (rotation_index >> 8) & 0xFF,
+ rotation_index & 0xFF};
+
+ size_t diversifier_size = rotation_index == 0 ? 5 : 7;
+
+ hmac_sha256(master_key, master_key_length, diversifier, diversifier_size,
dest);
}
secbool secret_key_derive_sym(uint8_t slot, uint16_t index, uint16_t subindex,
+ uint16_t rotation_index,
uint8_t dest[SHA256_DIGEST_LENGTH]) {
secbool ret = sectrue;
@@ -73,8 +87,8 @@ secbool secret_key_derive_sym(uint8_t slot, uint16_t index, uint16_t subindex,
goto cleanup;
}
- diversify_and_derive(index, subindex, master_key.bytes, master_key.size,
- dest);
+ diversify_and_derive(index, subindex, rotation_index, master_key.bytes,
+ master_key.size, dest);
cleanup:
memzero(master_key.bytes, master_key.size);
@@ -82,6 +96,7 @@ cleanup:
}
secbool secret_key_derive_nist256p1(uint8_t slot, uint16_t index,
+ uint16_t rotation_index,
uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
// `slot` argument is not used unless SECRET_PRIVILEGED_MASTER_KEY_SLOT is
// defined
@@ -91,7 +106,7 @@ secbool secret_key_derive_nist256p1(uint8_t slot, uint16_t index,
secbool ret = sectrue;
bignum256 s = {0};
for (uint16_t i = 0; i < 10000; i++) {
- ret = secret_key_derive_sym(slot, index, i, dest);
+ ret = secret_key_derive_sym(slot, index, i, rotation_index, dest);
if (ret != sectrue) {
goto cleanup;
}
diff --git a/core/embed/sec/secret_keys/secret_keys_common.h b/core/embed/sec/secret_keys/secret_keys_common.h
index 5c8540c8..8d949cbf 100644
--- a/core/embed/sec/secret_keys/secret_keys_common.h
+++ b/core/embed/sec/secret_keys/secret_keys_common.h
@@ -43,9 +43,11 @@
#endif // SECRET_PRIVILEGED_MASTER_KEY_SLOT
secbool secret_key_derive_sym(uint8_t slot, uint16_t index, uint16_t subindex,
+ uint16_t rotation_index,
uint8_t dest[SHA256_DIGEST_LENGTH]);
secbool secret_key_derive_nist256p1(uint8_t slot, uint16_t index,
+ uint16_t rotation_index,
uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]);
#endif // SECURE_MODE
diff --git a/core/embed/sec/secret_keys/stm32f4/secret_keys.c b/core/embed/sec/secret_keys/stm32f4/secret_keys.c
index ccd99a24..02607520 100644
--- a/core/embed/sec/secret_keys/stm32f4/secret_keys.c
+++ b/core/embed/sec/secret_keys/stm32f4/secret_keys.c
@@ -39,10 +39,10 @@ secbool secret_key_optiga_pairing(uint8_t dest[OPTIGA_PAIRING_SECRET_SIZE]) {
#endif // USE_OPTIGA
-secbool secret_key_delegated_identity(uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
- secret_key_derive_nist256p1(UNUSED_KEY_SLOT, KEY_INDEX_DELEGATED_IDENTITY,
- dest);
- return sectrue;
+secbool secret_key_delegated_identity(uint16_t rotation_index,
+ uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
+ return secret_key_derive_nist256p1(
+ UNUSED_KEY_SLOT, KEY_INDEX_DELEGATED_IDENTITY, rotation_index, dest);
}
secbool secret_key_master_key_get(secret_key_master_key_t* master_key) {
diff --git a/core/embed/sec/secret_keys/stm32u5/secret_keys.c b/core/embed/sec/secret_keys/stm32u5/secret_keys.c
index c68e338d..90dcf1af 100644
--- a/core/embed/sec/secret_keys/stm32u5/secret_keys.c
+++ b/core/embed/sec/secret_keys/stm32u5/secret_keys.c
@@ -39,26 +39,28 @@
secbool secret_key_mcu_device_auth(uint8_t dest[MLDSA_SEEDBYTES]) {
_Static_assert(MLDSA_SEEDBYTES == SHA256_DIGEST_LENGTH);
return secret_key_derive_sym(SECRET_PRIVILEGED_MASTER_KEY_SLOT,
- KEY_INDEX_MCU_DEVICE_AUTH, 0, dest);
+ KEY_INDEX_MCU_DEVICE_AUTH, 0, 0, dest);
}
#ifdef USE_OPTIGA
secbool secret_key_optiga_pairing(uint8_t dest[OPTIGA_PAIRING_SECRET_SIZE]) {
_Static_assert(OPTIGA_PAIRING_SECRET_SIZE == SHA256_DIGEST_LENGTH);
return secret_key_derive_sym(SECRET_PRIVILEGED_MASTER_KEY_SLOT,
- KEY_INDEX_OPTIGA_PAIRING, 0, dest);
+ KEY_INDEX_OPTIGA_PAIRING, 0, 0, dest);
}
secbool secret_key_optiga_masking(uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
return secret_key_derive_nist256p1(SECRET_PRIVILEGED_MASTER_KEY_SLOT,
- KEY_INDEX_OPTIGA_MASKING, dest);
+ KEY_INDEX_OPTIGA_MASKING, 0, dest);
}
#endif // USE_OPTIGA
-secbool secret_key_delegated_identity(uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
+secbool secret_key_delegated_identity(uint16_t rotation_index,
+ uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
return secret_key_derive_nist256p1(SECRET_UNPRIVILEGED_MASTER_KEY_SLOT,
- KEY_INDEX_DELEGATED_IDENTITY, dest);
+ KEY_INDEX_DELEGATED_IDENTITY,
+ rotation_index, dest);
}
#ifdef USE_TROPIC
@@ -66,7 +68,7 @@ static secbool secret_key_derive_curve25519(uint8_t slot, uint16_t index,
curve25519_key dest) {
_Static_assert(sizeof(curve25519_key) == SHA256_DIGEST_LENGTH);
- secbool ret = secret_key_derive_sym(slot, index, 0, dest);
+ secbool ret = secret_key_derive_sym(slot, index, 0, 0, dest);
dest[0] &= 248;
dest[31] &= 127;
dest[31] |= 64;
@@ -92,7 +94,7 @@ secbool secret_key_tropic_pairing_privileged(curve25519_key dest) {
secbool secret_key_tropic_masking(uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
return secret_key_derive_nist256p1(SECRET_PRIVILEGED_MASTER_KEY_SLOT,
- KEY_INDEX_TROPIC_MASKING, dest);
+ KEY_INDEX_TROPIC_MASKING, 0, dest);
}
#endif // USE_TROPIC
@@ -120,7 +122,7 @@ secbool secret_key_nrf_pairing(uint8_t dest[NRF_PAIRING_SECRET_SIZE]) {
}
return secret_key_derive_sym(SECRET_UNPRIVILEGED_MASTER_KEY_SLOT,
- KEY_INDEX_NRF_PAIRING, 0, dest);
+ KEY_INDEX_NRF_PAIRING, 0, 0, dest);
}
secbool secret_validate_nrf_pairing(const uint8_t* message, size_t msg_len,
@@ -130,7 +132,7 @@ secbool secret_validate_nrf_pairing(const uint8_t* message, size_t msg_len,
uint8_t key[NRF_PAIRING_SECRET_SIZE] = {0};
if (sectrue != secret_key_derive_sym(SECRET_UNPRIVILEGED_MASTER_KEY_SLOT,
- KEY_INDEX_NRF_PAIRING, 0, key)) {
+ KEY_INDEX_NRF_PAIRING, 0, 0, key)) {
return secfalse;
}
@@ -158,7 +160,7 @@ secbool secret_key_storage_salt(uint16_t fw_type,
uint8_t dest[SECRET_KEY_STORAGE_SALT_SIZE]) {
_Static_assert(SECRET_KEY_STORAGE_SALT_SIZE == SHA256_DIGEST_LENGTH);
return secret_key_derive_sym(SECRET_UNPRIVILEGED_MASTER_KEY_SLOT,
- KEY_INDEX_STORAGE_SALT, fw_type, dest);
+ KEY_INDEX_STORAGE_SALT, fw_type, 0, dest);
}
#else // SECRET_PRIVILEGED_MASTER_KEY_SLOT
@@ -191,9 +193,10 @@ secbool secret_key_master_key_get(secret_key_master_key_t* master_key) {
return sectrue;
}
-secbool secret_key_delegated_identity(uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
- return secret_key_derive_nist256p1(UNUSED_KEY_SLOT,
- KEY_INDEX_DELEGATED_IDENTITY, dest);
+secbool secret_key_delegated_identity(uint16_t rotation_index,
+ uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
+ return secret_key_derive_nist256p1(
+ UNUSED_KEY_SLOT, KEY_INDEX_DELEGATED_IDENTITY, rotation_index, dest);
}
#endif // SECRET_PRIVILEGED_MASTER_KEY_SLOT
diff --git a/core/embed/sec/secret_keys/unix/secret_keys.c b/core/embed/sec/secret_keys/unix/secret_keys.c
index 1cbeb97c..30e44e63 100644
--- a/core/embed/sec/secret_keys/unix/secret_keys.c
+++ b/core/embed/sec/secret_keys/unix/secret_keys.c
@@ -72,14 +72,15 @@ secbool secret_key_tropic_masking(uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
#endif // USE_TROPIC
-secbool secret_key_delegated_identity(uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
+secbool secret_key_delegated_identity(uint16_t rotation_index,
+ uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
#ifdef SECRET_UNPRIVILEGED_MASTER_KEY_SLOT
static uint8_t key_slot = SECRET_UNPRIVILEGED_MASTER_KEY_SLOT;
#else
static uint8_t key_slot = UNUSED_KEY_SLOT;
#endif
return secret_key_derive_nist256p1(key_slot, KEY_INDEX_DELEGATED_IDENTITY,
- dest);
+ rotation_index, dest);
}
secbool secret_key_master_key_get(secret_key_master_key_t* master_key) {
diff --git a/core/embed/sys/smcall/stm32/smcall_dispatch.c b/core/embed/sys/smcall/stm32/smcall_dispatch.c
index f875cf61..8536463c 100644
--- a/core/embed/sys/smcall/stm32/smcall_dispatch.c
+++ b/core/embed/sys/smcall/stm32/smcall_dispatch.c
@@ -222,8 +222,9 @@ __attribute((no_stack_protector)) void smcall_handler(uint32_t *args,
#ifdef USE_SECRET_KEYS
case SMCALL_SECRET_KEYS_GET_DELEGATED_IDENTITY_KEY: {
- uint8_t *dest = (uint8_t *)args[0];
- args[0] = secret_key_delegated_identity__verified(dest);
+ uint16_t rotation_index = args[0];
+ uint8_t *dest = (uint8_t *)args[1];
+ args[0] = secret_key_delegated_identity__verified(rotation_index, dest);
} break;
#endif
diff --git a/core/embed/sys/smcall/stm32/smcall_stubs.c b/core/embed/sys/smcall/stm32/smcall_stubs.c
index f814913f..f411fae3 100644
--- a/core/embed/sys/smcall/stm32/smcall_stubs.c
+++ b/core/embed/sys/smcall/stm32/smcall_stubs.c
@@ -221,8 +221,9 @@ void optiga_set_sec_max(void) { smcall_invoke0(SMCALL_OPTIGA_SET_SEC_MAX); }
#ifdef USE_SECRET_KEYS
#include <sec/secret_keys.h>
-secbool secret_key_delegated_identity(uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
- return (secbool)smcall_invoke1((uint32_t)dest,
+secbool secret_key_delegated_identity(uint16_t rotation_index,
+ uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
+ return (secbool)smcall_invoke2(rotation_index, (uint32_t)dest,
SMCALL_SECRET_KEYS_GET_DELEGATED_IDENTITY_KEY);
}
diff --git a/core/embed/sys/smcall/stm32/smcall_verifiers.c b/core/embed/sys/smcall/stm32/smcall_verifiers.c
index 7574de46..1316bb12 100644
--- a/core/embed/sys/smcall/stm32/smcall_verifiers.c
+++ b/core/embed/sys/smcall/stm32/smcall_verifiers.c
@@ -222,12 +222,12 @@ access_violation:
#include <sec/secret_keys.h>
secbool secret_key_delegated_identity__verified(
- uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
+ uint16_t rotation_index, uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
if (!probe_write_access(dest, ECDSA_PRIVATE_KEY_SIZE)) {
goto access_violation;
}
- return secret_key_delegated_identity(dest);
+ return secret_key_delegated_identity(rotation_index, dest);
access_violation:
apptask_access_violation();
diff --git a/core/embed/sys/smcall/stm32/smcall_verifiers.h b/core/embed/sys/smcall/stm32/smcall_verifiers.h
index 87a75c2a..eac8bb8d 100644
--- a/core/embed/sys/smcall/stm32/smcall_verifiers.h
+++ b/core/embed/sys/smcall/stm32/smcall_verifiers.h
@@ -77,7 +77,7 @@ bool __wur optiga_read_sec__verified(uint8_t *sec);
#include <sec/secret_keys.h>
secbool secret_key_delegated_identity__verified(
- uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]);
+ uint16_t rotation_index, uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]);
#endif
// ---------------------------------------------------------------------
diff --git a/core/embed/sys/syscall/stm32/syscall_dispatch.c b/core/embed/sys/syscall/stm32/syscall_dispatch.c
index 9b6d6d40..e7f97e49 100644
--- a/core/embed/sys/syscall/stm32/syscall_dispatch.c
+++ b/core/embed/sys/syscall/stm32/syscall_dispatch.c
@@ -502,8 +502,9 @@ __attribute((no_stack_protector)) void syscall_handler(uint32_t *args,
#ifdef USE_SECRET_KEYS
case SYSCALL_SECRET_KEYS_GET_DELEGATED_IDENTITY_KEY: {
- uint8_t *dest = (uint8_t *)args[0];
- args[0] = secret_key_delegated_identity__verified(dest);
+ uint16_t rotation_index = args[0];
+ uint8_t *dest = (uint8_t *)args[1];
+ args[0] = secret_key_delegated_identity__verified(rotation_index, dest);
} break;
#endif
diff --git a/core/embed/sys/syscall/stm32/syscall_stubs.c b/core/embed/sys/syscall/stm32/syscall_stubs.c
index 7d704039..42917f88 100644
--- a/core/embed/sys/syscall/stm32/syscall_stubs.c
+++ b/core/embed/sys/syscall/stm32/syscall_stubs.c
@@ -354,20 +354,6 @@ secbool secret_bootloader_locked(void) {
#endif
#endif
-// =============================================================================
-// secret_keys.h
-// =============================================================================
-
-#ifdef USE_SECRET_KEYS
-#include <sec/secret_keys.h>
-
-secbool secret_key_delegated_identity(uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
- return (secbool)syscall_invoke1(
- (uint32_t)dest, SYSCALL_SECRET_KEYS_GET_DELEGATED_IDENTITY_KEY);
-}
-
-#endif
-
// =============================================================================
// button.h
// =============================================================================
@@ -501,6 +487,21 @@ void optiga_set_sec_max(void) { syscall_invoke0(SYSCALL_OPTIGA_SET_SEC_MAX); }
#endif // USE_OPTIGA
+// =============================================================================
+// secret_keys.h
+// =============================================================================
+
+#ifdef USE_SECRET_KEYS
+#include <sec/secret_keys.h>
+
+secbool secret_key_delegated_identity(uint16_t rotation_index,
+ uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
+ return (secbool)syscall_invoke2(
+ rotation_index, (uint32_t)dest,
+ SYSCALL_SECRET_KEYS_GET_DELEGATED_IDENTITY_KEY);
+}
+#endif
+
// =============================================================================
// telemetry.h
// =============================================================================
diff --git a/core/embed/sys/syscall/stm32/syscall_verifiers.c b/core/embed/sys/syscall/stm32/syscall_verifiers.c
index c464eff7..3409c6aa 100644
--- a/core/embed/sys/syscall/stm32/syscall_verifiers.c
+++ b/core/embed/sys/syscall/stm32/syscall_verifiers.c
@@ -586,12 +586,12 @@ access_violation:
#include <sec/secret_keys.h>
secbool secret_key_delegated_identity__verified(
- uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
+ uint16_t rotation_index, uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]) {
if (!probe_write_access(dest, ECDSA_PRIVATE_KEY_SIZE)) {
goto access_violation;
}
- return secret_key_delegated_identity(dest);
+ return secret_key_delegated_identity(rotation_index, dest);
access_violation:
apptask_access_violation();
diff --git a/core/embed/sys/syscall/stm32/syscall_verifiers.h b/core/embed/sys/syscall/stm32/syscall_verifiers.h
index 2e7088f8..53a9b8f4 100644
--- a/core/embed/sys/syscall/stm32/syscall_verifiers.h
+++ b/core/embed/sys/syscall/stm32/syscall_verifiers.h
@@ -166,7 +166,7 @@ bool __wur optiga_read_sec__verified(uint8_t *sec);
#include <sec/secret_keys.h>
secbool secret_key_delegated_identity__verified(
- uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]);
+ uint16_t index, uint8_t dest[ECDSA_PRIVATE_KEY_SIZE]);
#endif
// ---------------------------------------------------------------------
diff --git a/core/embed/upymod/modtrezorutils/modtrezorutils.c b/core/embed/upymod/modtrezorutils/modtrezorutils.c
index 67c2a323..ca1b643b 100644
--- a/core/embed/upymod/modtrezorutils/modtrezorutils.c
+++ b/core/embed/upymod/modtrezorutils/modtrezorutils.c
@@ -269,20 +269,21 @@ STATIC mp_obj_t mod_trezorutils_firmware_vendor(void) {
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorutils_firmware_vendor_obj,
mod_trezorutils_firmware_vendor);
-/// def delegated_identity() -> bytes:
+/// def delegated_identity(rotation_index: int) -> bytes:
/// """
/// Returns the delegated identity key used for registration and space
-/// management at Evolu.
+/// management at Quota Manager.
/// """
-STATIC mp_obj_t mod_trezorutils_delegated_identity(void) {
+STATIC mp_obj_t mod_trezorutils_delegated_identity(mp_obj_t index) {
+ uint16_t rotation_index = trezor_obj_get_uint16(index);
uint8_t private_key[ECDSA_PRIVATE_KEY_SIZE] = {0};
- if (secret_key_delegated_identity(private_key) != sectrue) {
+ if (secret_key_delegated_identity(rotation_index, private_key) != sectrue) {
mp_raise_msg(&mp_type_RuntimeError,
MP_ERROR_TEXT("Failed to read delegated identity."));
}
return mp_obj_new_bytes(private_key, sizeof(private_key));
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorutils_delegated_identity_obj,
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorutils_delegated_identity_obj,
mod_trezorutils_delegated_identity);
/// def unit_color() -> int | None:
diff --git a/core/embed/upymod/qstrdefsport.h b/core/embed/upymod/qstrdefsport.h
index 59463e6e..16ccf556 100644
--- a/core/embed/upymod/qstrdefsport.h
+++ b/core/embed/upymod/qstrdefsport.h
@@ -126,6 +126,7 @@ Q(apps.evolu)
Q(apps.evolu.common)
Q(apps.evolu.get_delegated_identity_key)
Q(apps.evolu.get_node)
+Q(apps.evolu.index_management)
Q(apps.evolu.sign_registration_request)
Q(apps.homescreen)
Q(apps.homescreen.device_menu)
@@ -244,6 +245,7 @@ Q(hash_benchmark)
Q(hashlib)
Q(helpers)
Q(homescreen)
+Q(index_management)
Q(keychain)
Q(layout)
Q(layouts)
diff --git a/core/embed/upymod/trezorobj.h b/core/embed/upymod/trezorobj.h
index db73d9c8..825f229d 100644
--- a/core/embed/upymod/trezorobj.h
+++ b/core/embed/upymod/trezorobj.h
@@ -79,6 +79,15 @@ static inline uint8_t trezor_obj_get_uint8(mp_obj_t obj) {
return u;
}
+static inline uint16_t trezor_obj_get_uint16(mp_obj_t obj) {
+ mp_uint_t u = trezor_obj_get_uint(obj);
+ if (u > 0xFFFF) {
+ mp_raise_msg(&mp_type_OverflowError,
+ MP_ERROR_TEXT("value does not fit into uint16 type"));
+ }
+ return (uint16_t)u;
+}
+
static inline uint64_t trezor_obj_get_uint64(mp_const_obj_t obj) {
if (MP_OBJ_IS_SMALL_INT(obj)) {
mp_int_t i = MP_OBJ_SMALL_INT_VALUE(obj);
diff --git a/core/mocks/generated/trezorutils.pyi b/core/mocks/generated/trezorutils.pyi
index 29082256..29c48f8c 100644
--- a/core/mocks/generated/trezorutils.pyi
+++ b/core/mocks/generated/trezorutils.pyi
@@ -81,10 +81,10 @@ def firmware_vendor() -> str:
# upymod/modtrezorutils/modtrezorutils.c
-def delegated_identity() -> bytes:
+def delegated_identity(rotation_index: int) -> bytes:
"""
Returns the delegated identity key used for registration and space
- management at Evolu.
+ management at Quota Manager.
"""
diff --git a/core/mocks/trezortranslate_keys.pyi b/core/mocks/trezortranslate_keys.pyi
index c776e6b0..2a850e66 100644
--- a/core/mocks/trezortranslate_keys.pyi
+++ b/core/mocks/trezortranslate_keys.pyi
@@ -814,9 +814,6 @@ class TR:
sd_card__use_different_card: str = "Use a different card or format the SD card to the FAT32 filesystem."
sd_card__wanna_format: str = "Do you really want to format the SD card?"
sd_card__wrong_sd_card: str = "Wrong SD card."
- secure_sync__delegated_identity_key_no_thp: str = "Allow Trezor Suite to use Suite Sync with this Trezor?"
- secure_sync__delegated_identity_key_thp: str = "Allow {0} on {1} to use Suite Sync with this Trezor?"
- secure_sync__header: str = "Suite Sync"
send__cancel_sign: str = "Cancel sign"
send__cancel_transaction: str = "Cancel transaction"
send__confirm_sending: str = "Sending amount"
@@ -951,6 +948,10 @@ class TR:
storage_msg__starting: str = "Starting up"
storage_msg__verifying_pin: str = "Verifying PIN"
storage_msg__wrong_pin: str = "Wrong PIN"
+ suite_sync__delegated_identity_key_no_thp: str = "Allow Trezor Suite to use Suite Sync with this Trezor?"
+ suite_sync__delegated_identity_key_thp: str = "Allow {0} on {1} to use Suite Sync with this Trezor?"
+ suite_sync__header: str = "Suite Sync"
+ suite_sync__rotate_key: str = "You are about to rotate the delegated identity key used for Suite Sync. This will invalidate previous keys. Do you want to proceed?"
tezos__baker_address: str = "Baker address"
tezos__balance: str = "Balance"
tezos__ballot: str = "Ballot"
diff --git a/core/src/apps/evolu/common.py b/core/src/apps/evolu/common.py
index b50decc9..236c6423 100644
--- a/core/src/apps/evolu/common.py
+++ b/core/src/apps/evolu/common.py
@@ -1,9 +1,20 @@
+from micropython import const
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from buffer_types import AnyBytes
from typing import Sequence
+ROTATION_INDEX_LIMIT = const((1 << 16) - 1)
+
+
+def check_delegated_identity_rotation_index(rotation_index: int | None) -> None:
+ if rotation_index is not None:
+ if not 0 <= rotation_index <= ROTATION_INDEX_LIMIT:
+ raise ValueError(
+ f"Rotation index must be between 0 and {ROTATION_INDEX_LIMIT}"
+ )
+
def check_delegated_identity_proof(
provided_proof: AnyBytes,
@@ -12,13 +23,15 @@ def check_delegated_identity_proof(
) -> bool:
from trezorutils import delegated_identity
+ from storage.device import get_delegated_identity_key_rotation_index
from trezor.crypto.curve import nist256p1
from trezor.crypto.hashlib import sha256
from trezor.utils import HashWriter
from apps.common.writers import write_compact_size
- private_key = delegated_identity()
+ delegated_identity_rotation_index = get_delegated_identity_key_rotation_index() or 0
+ private_key = delegated_identity(delegated_identity_rotation_index)
public_key = get_public_key_from_private_key(private_key)
hash_writer = HashWriter(sha256())
diff --git a/core/src/apps/evolu/get_delegated_identity_key.py b/core/src/apps/evolu/get_delegated_identity_key.py
index 7acca6cf..677f56a7 100644
--- a/core/src/apps/evolu/get_delegated_identity_key.py
+++ b/core/src/apps/evolu/get_delegated_identity_key.py
@@ -32,15 +32,54 @@ async def get_delegated_identity_key(
from trezorutils import delegated_identity
from trezor.messages import EvoluDelegatedIdentityKey
+ from trezor.wire.errors import DataError
- if utils.USE_THP:
- await confirm_thp(msg)
+ from .common import check_delegated_identity_rotation_index
+
+ if msg.rotate and msg.rotation_index is not None:
+ raise DataError("Cannot rotate and request a specific index simultaneously")
+ check_delegated_identity_rotation_index(msg.rotation_index)
+
+ if msg.rotate:
+ await rotate_index()
else:
- await confirm_no_thp()
+ if utils.USE_THP:
+ await confirm_thp(msg)
+ else:
+ await confirm_no_thp()
+
+ rotation_index = get_rotation_index(msg)
+ private_key = delegated_identity(rotation_index or 0)
+
+ return EvoluDelegatedIdentityKey(
+ private_key=private_key, rotation_index=rotation_index
+ )
+
- private_key = delegated_identity()
+async def confirm_thp(msg: EvoluGetDelegatedIdentityKey) -> None:
+ from trezor import TR
+ from trezor.ui.layouts import confirm_action
+ from trezor.wire.context import get_channel_context
+ from trezor.wire.errors import DataError
+
+ from apps.thp.credential_manager import decode_credential, validate_credential
- return EvoluDelegatedIdentityKey(private_key=private_key)
+ if msg.thp_credential is None:
+ raise DataError("THP credential must be provided when THP is enabled")
+ credential_received = decode_credential(msg.thp_credential)
+ host_static_public_key = (
+ get_channel_context().channel_cache.get_host_static_public_key()
+ )
+ if not validate_credential(credential_received, host_static_public_key):
+ raise DataError("Invalid credential")
+
+ app_name = credential_received.cred_metadata.app_name
+ host_name = credential_received.cred_metadata.host_name
+ await confirm_action(
+ "suite_sync",
+ TR.suite_sync__header,
+ TR.suite_sync__delegated_identity_key_thp.format(app_name, host_name),
+ )
async def confirm_no_thp() -> None:
@@ -48,36 +87,49 @@ async def confirm_no_thp() -> None:
from trezor.ui.layouts import confirm_action
await confirm_action(
- "secure_sync",
- TR.secure_sync__header,
- TR.secure_sync__delegated_identity_key_no_thp,
+ "suite_sync",
+ TR.suite_sync__header,
+ TR.suite_sync__delegated_identity_key_no_thp,
)
-if utils.USE_THP:
+def get_rotation_index(msg: EvoluGetDelegatedIdentityKey) -> int | None:
+ from storage.device import get_delegated_identity_key_rotation_index
+ from trezor.wire.errors import DataError
+
+ rotation_index = get_delegated_identity_key_rotation_index()
+
+ if isinstance(msg.rotation_index, int):
+ if msg.rotation_index <= (rotation_index or 0):
+ rotation_index = msg.rotation_index
+ else:
+ raise DataError(
+ f"Requested rotation index ({msg.rotation_index}) is higher than the current rotation index ({rotation_index})"
+ )
- async def confirm_thp(msg: EvoluGetDelegatedIdentityKey) -> None:
- from trezor import TR
- from trezor.ui.layouts import confirm_action
- from trezor.wire.context import get_channel_context
- from trezor.wire.errors import DataError
+ return rotation_index
- from apps.thp.credential_manager import decode_credential, validate_credential
- if msg.thp_credential is None:
- raise DataError("THP credential must be provided when THP is enabled")
- credential_received = decode_credential(msg.thp_credential)
- host_static_public_key = (
- get_channel_context().channel_cache.get_host_static_public_key()
- )
+async def rotate_index() -> None:
+ from storage.device import (
+ get_delegated_identity_key_rotation_index,
+ set_delegated_identity_key_rotation_index,
+ )
+ from trezor import TR
+ from trezor.ui.layouts import confirm_action
+ from trezor.wire.errors import DataError
- if not validate_credential(credential_received, host_static_public_key):
- raise DataError("Invalid credential")
+ from .common import ROTATION_INDEX_LIMIT
+
+ rotation_index = get_delegated_identity_key_rotation_index() or 0
+
+ if rotation_index + 1 > ROTATION_INDEX_LIMIT:
+ raise DataError("Maximum rotation index reached")
+
+ await confirm_action(
+ "suite_sync",
+ TR.suite_sync__header,
+ TR.suite_sync__rotate_key,
+ )
- app_name = credential_received.cred_metadata.app_name
- host_name = credential_received.cred_metadata.host_name
- await confirm_action(
- "secure_sync",
- TR.secure_sync__header,
- TR.secure_sync__delegated_identity_key_thp.format(app_name, host_name),
- )
+ set_delegated_identity_key_rotation_index(rotation_index + 1)
diff --git a/core/src/apps/evolu/get_node.py b/core/src/apps/evolu/get_node.py
index 09529ec4..072a1b17 100644
--- a/core/src/apps/evolu/get_node.py
+++ b/core/src/apps/evolu/get_node.py
@@ -4,6 +4,7 @@ if TYPE_CHECKING:
from trezor.messages import EvoluGetNode, EvoluNode
_EVOLU_KEY_PATH_PREFIX = [b"TREZOR", b"Evolu"]
+_EVOLU_KEY_PATH_PREFIX_INDEX = [b"TREZOR", b"Evolu Index"]
async def get_node(msg: EvoluGetNode) -> EvoluNode:
@@ -32,20 +33,36 @@ async def get_node(msg: EvoluGetNode) -> EvoluNode:
raise NotInitialized("Device is not initialized")
if not check_delegated_identity_proof(
- bytes(msg.proof_of_delegated_identity), header=b"EvoluGetNode"
+ bytes(msg.proof_of_delegated_identity),
+ header=b"EvoluGetNode",
):
raise ValueError("Invalid proof")
# TODO: adjust copy when the usage is exposed via Trezor Suite
- return EvoluNode(data=await derive_evolu_node())
-
-
-async def derive_evolu_node() -> bytes:
+ index = msg.node_rotation_index or 0
+ return EvoluNode(data=await derive_evolu_node(index))
+
+
+# The `node_rotation_index` is NOT protected like the `delegated_identity_key_index`.
+# A compromised application with access to the current `delegated_identity_key` can enumerate all possible nodes by calling this function with different indices.
+#
+# Rationale for this:
+# 1. This index is dependent on passphrase and thus we cannot store the index on the device due to plausible deniability.
+# 2. We cannot include the `delegated_identity_key_index` in the SLIP-21 path because we need to get the same node on the same seed regardless of the device.
+#
+# This index protects against a passive attacker who gains access to one of the nodes but not to the unlocked device.
+# Rotating the node to a new index then restricts the attacker's ability to read new labels.
+#
+# Note: The need for node rotation has diminished recently as we now handle data deletion through other mechanisms.
+async def derive_evolu_node(index: int) -> bytes:
from apps.common.seed import Slip21Node, get_seed
seed = await get_seed()
node = Slip21Node(seed)
- node.derive_path(_EVOLU_KEY_PATH_PREFIX)
+ if index == 0:
+ node.derive_path(_EVOLU_KEY_PATH_PREFIX)
+ else:
+ node.derive_path(_EVOLU_KEY_PATH_PREFIX_INDEX + [str(index).encode()])
return node.data
diff --git a/core/src/apps/evolu/index_management.py b/core/src/apps/evolu/index_management.py
new file mode 100644
index 00000000..55b9541a
--- /dev/null
+++ b/core/src/apps/evolu/index_management.py
@@ -0,0 +1,31 @@
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+ from trezor.messages import EvoluIndexManagement, EvoluIndexManagementResponse
+
+
+async def index_management(msg: EvoluIndexManagement) -> EvoluIndexManagementResponse:
+ """
+ Sets the delegated identity key rotation index if it is not already set.
+ Returns the current rotation index.
+ """
+ from storage.device import (
+ get_delegated_identity_key_rotation_index,
+ set_delegated_identity_key_rotation_index,
+ )
+ from trezor.messages import EvoluIndexManagementResponse
+
+ from .common import check_delegated_identity_rotation_index
+
+ check_delegated_identity_rotation_index(msg.rotation_index)
+
+ stored_index = get_delegated_identity_key_rotation_index()
+
+ if msg.rotation_index is not None:
+ if stored_index is None:
+ set_delegated_identity_key_rotation_index(msg.rotation_index)
+ stored_index = msg.rotation_index
+ else:
+ raise ValueError("Rotation index already set.")
+
+ return EvoluIndexManagementResponse(rotation_index=stored_index)
diff --git a/core/src/apps/evolu/sign_registration_request.py b/core/src/apps/evolu/sign_registration_request.py
index 003854b6..404f5ccc 100644
--- a/core/src/apps/evolu/sign_registration_request.py
+++ b/core/src/apps/evolu/sign_registration_request.py
@@ -85,6 +85,7 @@ def _check_data(challenge: AnyBytes, size: int) -> tuple[AnyBytes, bytes]:
def _get_signature(challenge_bytes: AnyBytes, size_bytes: bytes) -> bytes:
from trezorutils import delegated_identity
+ from storage.device import get_delegated_identity_key_rotation_index
from trezor import utils, wire
from trezor.crypto import optiga
from trezor.crypto.hashlib import sha256
@@ -93,7 +94,7 @@ def _get_signature(challenge_bytes: AnyBytes, size_bytes: bytes) -> bytes:
from .common import get_public_key_from_private_key
- private_key = delegated_identity()
+ private_key = delegated_identity(get_delegated_identity_key_rotation_index() or 0)
public_key = get_public_key_from_private_key(private_key)
header = b"EvoluSignRegistrationRequestV1:"
diff --git a/core/src/apps/workflow_handlers.py b/core/src/apps/workflow_handlers.py
index 3e3f89a1..44c1f3ca 100644
--- a/core/src/apps/workflow_handlers.py
+++ b/core/src/apps/workflow_handlers.py
@@ -109,16 +109,18 @@ def _find_message_handler_module(msg_type: int) -> str:
return "apps.misc.cipher_key_value"
if msg_type == MessageType.GetFirmwareHash:
return "apps.misc.get_firmware_hash"
+ if msg_type == MessageType.PaymentNotification:
+ return "apps.misc.payment_notification"
# evolu
if msg_type == MessageType.EvoluGetNode:
return "apps.evolu.get_node"
- if msg_type == MessageType.EvoluSignRegistrationRequest:
- return "apps.evolu.sign_registration_request"
if msg_type == MessageType.EvoluGetDelegatedIdentityKey:
return "apps.evolu.get_delegated_identity_key"
- if msg_type == MessageType.PaymentNotification:
- return "apps.misc.payment_notification"
+ if msg_type == MessageType.EvoluIndexManagement:
+ return "apps.evolu.index_management"
+ if utils.USE_OPTIGA and msg_type == MessageType.EvoluSignRegistrationRequest:
+ return "apps.evolu.sign_registration_request"
if not utils.BITCOIN_ONLY:
# When promoting the Nostr app to production-level
diff --git a/core/src/storage/device.py b/core/src/storage/device.py
index d580f7a8..72ab926b 100644
--- a/core/src/storage/device.py
+++ b/core/src/storage/device.py
@@ -51,6 +51,7 @@ if utils.USE_POWER_MANAGER:
_DISABLE_BLUETOOTH = const(0x24) # bool (0x01 or empty)
if not utils.BITCOIN_ONLY:
_BINARY_MNEMONIC = const(0x25) # bytes
+_DELEGATED_IDENTITY_KEY_ROTATION_INDEX = const(0x26) # int
SAFETY_CHECK_LEVEL_STRICT : Literal[0] = const(0)
@@ -536,3 +537,22 @@ if utils.USE_THP:
across reboots, unlike storage.cache.
"""
return common.get(_NAMESPACE, THP_PAIRED_NAMES)
+
+
+def get_delegated_identity_key_rotation_index() -> int | None:
+ """
+ Get the current delegated identity key rotation index.
+ """
+ rotation_index = common.get_uint16(
+ _NAMESPACE, _DELEGATED_IDENTITY_KEY_ROTATION_INDEX
+ )
+ return rotation_index
+
+
+def set_delegated_identity_key_rotation_index(rotation_index: int) -> None:
+ """
+ Set the current delegated identity key rotation index.
+ """
+ common.set_uint16(
+ _NAMESPACE, _DELEGATED_IDENTITY_KEY_ROTATION_INDEX, rotation_index
+ )
diff --git a/core/src/trezor/enums/MessageType.py b/core/src/trezor/enums/MessageType.py
index d57c6d2d..82740587 100644
--- a/core/src/trezor/enums/MessageType.py
+++ b/core/src/trezor/enums/MessageType.py
@@ -92,6 +92,8 @@ EvoluSignRegistrationRequest = 2102
EvoluRegistrationRequest = 2103
EvoluGetDelegatedIdentityKey = 2104
EvoluDelegatedIdentityKey = 2105
+EvoluIndexManagement = 2106
+EvoluIndexManagementResponse = 2107
BenchmarkListNames = 9100
BenchmarkNames = 9101
BenchmarkRun = 9102
diff --git a/core/src/trezor/enums/__init__.py b/core/src/trezor/enums/__init__.py
index 2f60ae3e..8355c4b3 100644
--- a/core/src/trezor/enums/__init__.py
+++ b/core/src/trezor/enums/__init__.py
@@ -652,6 +652,8 @@ if TYPE_CHECKING:
EvoluRegistrationRequest = 2103
EvoluGetDelegatedIdentityKey = 2104
EvoluDelegatedIdentityKey = 2105
+ EvoluIndexManagement = 2106
+ EvoluIndexManagementResponse = 2107
TronGetAddress = 2200
TronAddress = 2201
TronSignTx = 2202
diff --git a/core/src/trezor/messages.py b/core/src/trezor/messages.py
index 927c7ca0..1db53a13 100644
--- a/core/src/trezor/messages.py
+++ b/core/src/trezor/messages.py
@@ -4182,11 +4182,13 @@ if TYPE_CHECKING:
class EvoluGetNode(protobuf.MessageType):
proof_of_delegated_identity: "AnyBytes"
+ node_rotation_index: "int"
def __init__(
self,
*,
proof_of_delegated_identity: "AnyBytes",
+ node_rotation_index: "int | None" = None,
) -> None:
pass
@@ -4244,11 +4246,15 @@ if TYPE_CHECKING:
class EvoluGetDelegatedIdentityKey(protobuf.MessageType):
thp_credential: "AnyBytes | None"
+ rotation_index: "int | None"
+ rotate: "bool | None"
def __init__(
self,
*,
thp_credential: "AnyBytes | None" = None,
+ rotation_index: "int | None" = None,
+ rotate: "bool | None" = None,
) -> None:
pass
@@ -4258,11 +4264,13 @@ if TYPE_CHECKING:
class EvoluDelegatedIdentityKey(protobuf.MessageType):
private_key: "AnyBytes"
+ rotation_index: "int | None"
def __init__(
self,
*,
private_key: "AnyBytes",
+ rotation_index: "int | None" = None,
) -> None:
pass
@@ -4270,6 +4278,34 @@ if TYPE_CHECKING:
def is_type_of(cls, msg: Any) -> TypeGuard["EvoluDelegatedIdentityKey"]:
return isinstance(msg, cls)
+ class EvoluIndexManagement(protobuf.MessageType):
+ rotation_index: "int | None"
+
+ def __init__(
+ self,
+ *,
+ rotation_index: "int | None" = None,
+ ) -> None:
+ pass
+
+ @classmethod
+ def is_type_of(cls, msg: Any) -> TypeGuard["EvoluIndexManagement"]:
+ return isinstance(msg, cls)
+
+ class EvoluIndexManagementResponse(protobuf.MessageType):
+ rotation_index: "int | None"
+
+ def __init__(
+ self,
+ *,
+ rotation_index: "int | None" = None,
+ ) -> None:
+ pass
+
+ @classmethod
+ def is_type_of(cls, msg: Any) -> TypeGuard["EvoluIndexManagementResponse"]:
+ return isinstance(msg, cls)
+
class MoneroTransactionSourceEntry(protobuf.MessageType):
outputs: "list[MoneroOutputEntry]"
real_output: "int | None"
diff --git a/core/tests/test_apps.evolu.check_evolu.py b/core/tests/test_apps.evolu.check_evolu.py
index c324e64c..8e8f4c43 100644
--- a/core/tests/test_apps.evolu.check_evolu.py
+++ b/core/tests/test_apps.evolu.check_evolu.py
@@ -3,12 +3,13 @@ from common import * # isort:skip
@unittest.skipUnless(utils.USE_OPTIGA, "only needed with Optiga")
-class TestCheckDelegatedIdentityKey(unittest.TestCase):
+class TestCheckEvoluCommandsRegistrationRequest(unittest.TestCase):
- def test_sign_registration_request(self):
+ def test_proof_sign_registration_request(self):
from trezorutils import delegated_identity
from ubinascii import unhexlify
+ from storage.device import get_delegated_identity_key_rotation_index
from trezor.crypto.curve import nist256p1
from trezor.crypto.hashlib import sha256
from trezor.utils import HashWriter
@@ -33,13 +34,13 @@ class TestCheckDelegatedIdentityKey(unittest.TestCase):
write_compact_size(h, len(arg))
h.extend(arg)
proof = nist256p1.sign(
- delegated_identity(),
+ delegated_identity(get_delegated_identity_key_rotation_index() or 0),
h.get_digest(),
)
self.assertTrue(check_delegated_identity_proof(proof, header, arguments))
- def test_sign_registration_request_invalid_size(self):
+ def test_proof_sign_registration_request_invalid_size(self):
from ubinascii import unhexlify
from trezor.wire import DataError
@@ -57,7 +58,7 @@ class TestCheckDelegatedIdentityKey(unittest.TestCase):
with self.assertRaises(DataError):
_check_data(sign_request_challenge, sign_request_size)
- def test_sign_registration_request_invalid_challenge(self):
+ def test_proof_sign_registration_request_invalid_challenge(self):
from trezor.wire import DataError
from apps.evolu.sign_registration_request import _check_data
@@ -68,9 +69,12 @@ class TestCheckDelegatedIdentityKey(unittest.TestCase):
with self.assertRaises(DataError):
_check_data(sign_request_challenge, sign_request_size)
- def test_get_evolu_node(self):
+
+class TestCheckEvoluCommandsGetNode(unittest.TestCase):
+ def test_proof_get_evolu_node(self):
from trezorutils import delegated_identity
+ from storage.device import get_delegated_identity_key_rotation_index
from trezor.crypto.curve import nist256p1
from trezor.crypto.hashlib import sha256
from trezor.utils import HashWriter
@@ -79,7 +83,6 @@ class TestCheckDelegatedIdentityKey(unittest.TestCase):
from apps.evolu.common import check_delegated_identity_proof
# get_node
-
header = b"EvoluGetNode"
h = HashWriter(sha256())
@@ -87,7 +90,7 @@ class TestCheckDelegatedIdentityKey(unittest.TestCase):
h.extend(header)
proof = nist256p1.sign(
- delegated_identity(),
+ delegated_identity(get_delegated_identity_key_rotation_index() or 0),
h.get_digest(),
)
diff --git a/core/translations/cs.json b/core/translations/cs.json
index d4ffabad..2bd5d528 100644
--- a/core/translations/cs.json
+++ b/core/translations/cs.json
@@ -2153,9 +2153,6 @@
"Delizia": "Nesprávná SD karta.",
"Eckhart": ""
},
- "secure_sync__delegated_identity_key_no_thp": "Povolit Trezor Suite používat Suite Sync s tímto Trezorem?",
- "secure_sync__delegated_identity_key_thp": "Povolit {0} na {1} používat Suite Sync s tímto Trezorem?",
- "secure_sync__header": "Suite Sync",
"send__cancel_sign": "Zrušit podpis",
"send__cancel_transaction": "Zrušit transakci",
"send__confirm_sending": "Odesílání částky",
@@ -2335,6 +2332,9 @@
"Eckhart": "Ověřování PINu..."
},
"storage_msg__wrong_pin": "Špatný PIN",
+ "suite_sync__delegated_identity_key_no_thp": "Povolit Trezor Suite používat Suite Sync s tímto Trezorem?",
+ "suite_sync__delegated_identity_key_thp": "Povolit {0} na {1} používat Suite Sync s tímto Trezorem?",
+ "suite_sync__header": "Suite Sync",
"tezos__baker_address": "Adresa bakera",
"tezos__balance": "Zůstatek",
"tezos__ballot": "Hlas",
diff --git a/core/translations/de.json b/core/translations/de.json
index e40f0e54..c99cf6e1 100644
--- a/core/translations/de.json
+++ b/core/translations/de.json
@@ -2658,9 +2658,6 @@
"Delizia": "Falsche SD-Karte.",
"Eckhart": ""
},
- "secure_sync__delegated_identity_key_no_thp": "Trezor Suite erlauben, Suite Sync mit diesem Trezor zu verwenden?",
- "secure_sync__delegated_identity_key_thp": "{0} auf {1} erlauben, Suite Sync mit diesem Trezor zu verwenden?",
- "secure_sync__header": "Suite Sync",
"send__cancel_sign": "Signieren abbrechen",
"send__cancel_transaction": "Transaktion abbrechen",
"send__confirm_sending": "Betrag senden",
@@ -2960,6 +2957,9 @@
"Eckhart": "PIN überprüfen..."
},
"storage_msg__wrong_pin": "Falscher PIN",
+ "suite_sync__delegated_identity_key_no_thp": "Trezor Suite erlauben, Suite Sync mit diesem Trezor zu verwenden?",
+ "suite_sync__delegated_identity_key_thp": "{0} auf {1} erlauben, Suite Sync mit diesem Trezor zu verwenden?",
+ "suite_sync__header": "Suite Sync",
"tezos__baker_address": "Baker-Adresse",
"tezos__balance": "Guthaben",
"tezos__ballot": "Abstimmung",
diff --git a/core/translations/en.json b/core/translations/en.json
index 159b7e27..f734812a 100644
--- a/core/translations/en.json
+++ b/core/translations/en.json
@@ -2121,9 +2121,6 @@
"Delizia": "Wrong SD card.",
"Eckhart": ""
},
- "secure_sync__delegated_identity_key_no_thp": "Allow Trezor Suite to use Suite Sync with this Trezor?",
- "secure_sync__delegated_identity_key_thp": "Allow {0} on {1} to use Suite Sync with this Trezor?",
- "secure_sync__header": "Suite Sync",
"send__cancel_sign": "Cancel sign",
"send__cancel_transaction": "Cancel transaction",
"send__confirm_sending": "Sending amount",
@@ -2303,6 +2300,10 @@
"Eckhart": "Verifying PIN..."
},
"storage_msg__wrong_pin": "Wrong PIN",
+ "suite_sync__delegated_identity_key_no_thp": "Allow Trezor Suite to use Suite Sync with this Trezor?",
+ "suite_sync__delegated_identity_key_thp": "Allow {0} on {1} to use Suite Sync with this Trezor?",
+ "suite_sync__header": "Suite Sync",
+ "suite_sync__rotate_key": "You are about to rotate the delegated identity key used for Suite Sync. This will invalidate previous keys. Do you want to proceed?",
"tezos__baker_address": "Baker address",
"tezos__balance": "Balance",
"tezos__ballot": "Ballot",
diff --git a/core/translations/es.json b/core/translations/es.json
index 005a7acc..4084442e 100644
--- a/core/translations/es.json
+++ b/core/translations/es.json
@@ -2178,9 +2178,6 @@
"Delizia": "Tarjeta SD incorrecta.",
"Eckhart": ""
},
- "secure_sync__delegated_identity_key_no_thp": "¿Permitir que Trezor Suite use Suite Sync con este Trezor?",
- "secure_sync__delegated_identity_key_thp": "¿Permitir que {0} en {1} use Suite Sync con este Trezor?",
- "secure_sync__header": "Suite Sync",
"send__cancel_sign": "Cancelar firma",
"send__cancel_transaction": "Cancelar transacción",
"send__confirm_sending": "Enviando importe",
@@ -2365,6 +2362,9 @@
"Eckhart": "Verificando PIN..."
},
"storage_msg__wrong_pin": "PIN incorrecto",
+ "suite_sync__delegated_identity_key_no_thp": "¿Permitir que Trezor Suite use Suite Sync con este Trezor?",
+ "suite_sync__delegated_identity_key_thp": "¿Permitir que {0} en {1} use Suite Sync con este Trezor?",
+ "suite_sync__header": "Suite Sync",
"tezos__baker_address": "Dirección del Baker",
"tezos__balance": "Saldo",
"tezos__ballot": "Voto",
diff --git a/core/translations/fr.json b/core/translations/fr.json
index bbff47fb..dda6bbc6 100644
--- a/core/translations/fr.json
+++ b/core/translations/fr.json
@@ -2428,9 +2428,6 @@
"Delizia": "Mauvaise carte SD.",
"Eckhart": ""
},
- "secure_sync__delegated_identity_key_no_thp": "Autoriser Trezor Suite à utiliser Suite Sync avec ce Trezor ?",
- "secure_sync__delegated_identity_key_thp": "Autoriser {0} sur {1} à utiliser Suite Sync avec ce Trezor ?",
- "secure_sync__header": "Suite Sync",
"send__cancel_sign": "Annuler la signature",
"send__cancel_transaction": "Annuler la transaction",
"send__confirm_sending": "Montant de l'envoi",
@@ -2620,6 +2617,9 @@
"Eckhart": "Vérification du PIN..."
},
"storage_msg__wrong_pin": "PIN incorrect",
+ "suite_sync__delegated_identity_key_no_thp": "Autoriser Trezor Suite à utiliser Suite Sync avec ce Trezor ?",
+ "suite_sync__delegated_identity_key_thp": "Autoriser {0} sur {1} à utiliser Suite Sync avec ce Trezor ?",
+ "suite_sync__header": "Suite Sync",
"tezos__baker_address": "Adresse du Baker",
"tezos__balance": "Solde",
"tezos__ballot": "Vote",
diff --git a/core/translations/order.json b/core/translations/order.json
index 2dfbef97..6d019455 100644
--- a/core/translations/order.json
+++ b/core/translations/order.json
@@ -1169,10 +1169,10 @@
"1167": "ble__must_be_enabled",
"1168": "ripple__destination_tag_missing",
"1169": "words__comm_trouble",
- "1170": "secure_sync__delegated_identity_key_no_thp",
- "1171": "secure_sync__delegated_identity_key_thp",
- "1172": "secure_sync__evolu_node_no_optiga",
- "1173": "secure_sync__header",
+ "1170": "suite_sync__delegated_identity_key_no_thp",
+ "1171": "suite_sync__delegated_identity_key_thp",
+ "1172": "suite_sync__evolu_node_no_optiga",
+ "1173": "suite_sync__header",
"1174": "words__note",
"1175": "words__fee_limit",
"1176": "ethereum__eip_7702_title",
@@ -1183,5 +1183,6 @@
"1181": "words__votes",
"1182": "words__voting",
"1183": "ethereum__confirm_contract",
- "1184": "words__intent"
+ "1184": "words__intent",
+ "1185": "suite_sync__rotate_key"
}
diff --git a/core/translations/pt.json b/core/translations/pt.json
index c3866edc..caecb032 100644
--- a/core/translations/pt.json
+++ b/core/translations/pt.json
@@ -2303,9 +2303,6 @@
"Delizia": "Cartão SD incorreto.",
"Eckhart": ""
},
- "secure_sync__delegated_identity_key_no_thp": "Permitir que o Trezor Suite use Suite Sync com este Trezor?",
- "secure_sync__delegated_identity_key_thp": "Permitir que {0} em {1} use Suite Sync com este Trezor?",
- "secure_sync__header": "Suite Sync",
"send__cancel_sign": "Cancelar assinatura",
"send__cancel_transaction": "Cancelar transação",
"send__confirm_sending": "Quantia de envio",
@@ -2495,6 +2492,9 @@
"Eckhart": "Verificando PIN..."
},
"storage_msg__wrong_pin": "PIN incorreto",
+ "suite_sync__delegated_identity_key_no_thp": "Permitir que o Trezor Suite use Suite Sync com este Trezor?",
+ "suite_sync__delegated_identity_key_thp": "Permitir que {0} em {1} use Suite Sync com este Trezor?",
+ "suite_sync__header": "Suite Sync",
"tezos__baker_address": "Endereço de baker",
"tezos__balance": "Saldo",
"tezos__ballot": "Voto",
diff --git a/core/translations/signatures.json b/core/translations/signatures.json
index caadbcb3..5a927c81 100644
--- a/core/translations/signatures.json
+++ b/core/translations/signatures.json
@@ -1,8 +1,8 @@
{
"current": {
- "merkle_root": "cce9cef94d67e56d732dfc2554baea86283fc50fbcf11272b7e33be1353425be",
- "datetime": "2026-03-24T09:34:36.736968+00:00",
- "commit": "623ccc38b087940c5354ba4cbb4176f875ede6ca"
+ "merkle_root": "e875770bb1cbb1197ad6c38d02a7839bbfe5dbace5a33d91567d285d784f7d1d",
+ "datetime": "2026-03-24T17:33:01.682981+00:00",
+ "commit": "a4a7c535fe37c4ba25bd1f44115144b9dad5cb55"
},
"history": [
{
diff --git a/python/src/trezorlib/cli/evolu.py b/python/src/trezorlib/cli/evolu.py
index 7996d928..5768a868 100644
--- a/python/src/trezorlib/cli/evolu.py
+++ b/python/src/trezorlib/cli/evolu.py
@@ -34,14 +34,20 @@ def cli() -> None:
@cli.command()
@click.argument("proof", type=str)
+@click.option("--node_index", "-i", type=int, default=0)
@with_session
def get_node(
session: Session,
proof: str,
+ node_index: int,
) -> str:
"""Return the SLIP-21 node for Evolu."""
proof_bytes = bytes.fromhex(proof)
- return evolu.get_node(session, proof=proof_bytes).hex()
+ return evolu.get_node(
+ session,
+ proof=proof_bytes,
+ node_rotation_index=node_index,
+ ).hex()
@cli.command()
@@ -70,12 +76,16 @@ def sign_registration_request(
@click.option("--credential", "-c", type=str)
+@click.option("--rotation_index", "-i", type=int)
+@click.option("--rotate", is_flag=True, help="Rotate the delegated identity key.")
@cli.command()
@with_session
def get_delegated_identity_key(
session: Session,
credential: Optional[str] = None,
-) -> str:
+ rotation_index: Optional[int] = None,
+ rotate: bool = False,
+) -> dict[str, str | int | None]:
"""
Request the delegated identity key of this device.
This key is used to prove the identity of the device at the Quota Manager server and to prove
@@ -84,7 +94,29 @@ def get_delegated_identity_key(
thp_credential = bytes.fromhex(credential) if credential else None
- return evolu.get_delegated_identity_key(
+ response = evolu.get_delegated_identity_key(
session=session,
+ rotation_index=rotation_index,
thp_credential=thp_credential,
- ).hex()
+ rotate=rotate,
+ )
+
+ return {
+ "key": response.private_key.hex(),
+ "rotation_index": response.rotation_index,
+ }
+
+
+@cli.command()
+@click.option("--rotation_index", "-i", type=int)
+@with_session
+def index_management(
+ session: Session,
+ rotation_index: Optional[int] = None,
+) -> str:
+ return str(
+ evolu.index_management(
+ session,
+ rotation_index=rotation_index,
+ ).rotation_index
+ )
diff --git a/python/src/trezorlib/evolu.py b/python/src/trezorlib/evolu.py
index 8063f2b7..08c73084 100644
--- a/python/src/trezorlib/evolu.py
+++ b/python/src/trezorlib/evolu.py
@@ -26,9 +26,16 @@ if TYPE_CHECKING:
@workflow()
-def get_node(session: Session, proof: bytes) -> bytes:
+def get_node(
+ session: Session,
+ proof: bytes,
+ node_rotation_index: Optional[int] = None,
+) -> bytes:
return session.call(
- messages.EvoluGetNode(proof_of_delegated_identity=proof),
+ messages.EvoluGetNode(
+ proof_of_delegated_identity=proof,
+ node_rotation_index=node_rotation_index,
+ ),
expect=messages.EvoluNode,
).data
@@ -48,12 +55,27 @@ def sign_registration_request(
def get_delegated_identity_key(
session: Session,
+ rotation_index: Optional[int] = None,
thp_credential: Optional[bytes] = None,
-) -> bytes:
-
+ rotate: Optional[bool] = False,
+) -> messages.EvoluDelegatedIdentityKey:
return session.call(
messages.EvoluGetDelegatedIdentityKey(
thp_credential=thp_credential,
+ rotation_index=rotation_index,
+ rotate=rotate,
),
expect=messages.EvoluDelegatedIdentityKey,
- ).private_key
+ )
+
+
+def index_management(
+ session: Session,
+ rotation_index: Optional[int] = None,
+) -> messages.EvoluIndexManagementResponse:
+ return session.call(
+ messages.EvoluIndexManagement(
+ rotation_index=rotation_index,
+ ),
+ expect=messages.EvoluIndexManagementResponse,
+ )
diff --git a/python/src/trezorlib/messages.py b/python/src/trezorlib/messages.py
index 2c0e9387..f21c6237 100644
--- a/python/src/trezorlib/messages.py
+++ b/python/src/trezorlib/messages.py
@@ -708,6 +708,8 @@ class MessageType(IntEnum):
EvoluRegistrationRequest = 2103
EvoluGetDelegatedIdentityKey = 2104
EvoluDelegatedIdentityKey = 2105
+ EvoluIndexManagement = 2106
+ EvoluIndexManagementResponse = 2107
TronGetAddress = 2200
TronAddress = 2201
TronSignTx = 2202
@@ -5676,14 +5678,17 @@ class EvoluGetNode(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 2100
FIELDS = {
1: protobuf.Field("proof_of_delegated_identity", "bytes", repeated=False, required=True),
+ 2: protobuf.Field("node_rotation_index", "uint32", repeated=False, required=False, default=0),
}
def __init__(
self,
*,
proof_of_delegated_identity: "bytes",
+ node_rotation_index: Optional["int"] = 0,
) -> None:
self.proof_of_delegated_identity = proof_of_delegated_identity
+ self.node_rotation_index = node_rotation_index
class EvoluNode(protobuf.MessageType):
@@ -5741,28 +5746,65 @@ class EvoluGetDelegatedIdentityKey(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 2104
FIELDS = {
1: protobuf.Field("thp_credential", "bytes", repeated=False, required=False, default=None),
+ 3: protobuf.Field("rotation_index", "uint32", repeated=False, required=False, default=None),
+ 4: protobuf.Field("rotate", "bool", repeated=False, required=False, default=None),
}
def __init__(
self,
*,
thp_credential: Optional["bytes"] = None,
+ rotation_index: Optional["int"] = None,
+ rotate: Optional["bool"] = None,
) -> None:
self.thp_credential = thp_credential
+ self.rotation_index = rotation_index
+ self.rotate = rotate
class EvoluDelegatedIdentityKey(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 2105
FIELDS = {
1: protobuf.Field("private_key", "bytes", repeated=False, required=True),
+ 2: protobuf.Field("rotation_index", "uint32", repeated=False, required=False, default=None),
}
def __init__(
self,
*,
private_key: "bytes",
+ rotation_index: Optional["int"] = None,
) -> None:
self.private_key = private_key
+ self.rotation_index = rotation_index
+
+
+class EvoluIndexManagement(protobuf.MessageType):
+ MESSAGE_WIRE_TYPE = 2106
+ FIELDS = {
+ 1: protobuf.Field("rotation_index", "uint32", repeated=False, required=False, default=None),
+ }
+
+ def __init__(
+ self,
+ *,
+ rotation_index: Optional["int"] = None,
+ ) -> None:
+ self.rotation_index = rotation_index
+
+
+class EvoluIndexManagementResponse(protobuf.MessageType):
+ MESSAGE_WIRE_TYPE = 2107
+ FIELDS = {
+ 1: protobuf.Field("rotation_index", "uint32", repeated=False, required=False, default=None),
+ }
+
+ def __init__(
+ self,
+ *,
+ rotation_index: Optional["int"] = None,
+ ) -> None:
+ self.rotation_index = rotation_index
class MoneroTransactionSourceEntry(protobuf.MessageType):
diff --git a/rust/trezor-client/src/messages/generated.rs b/rust/trezor-client/src/messages/generated.rs
index 93198042..243fdcd7 100644
--- a/rust/trezor-client/src/messages/generated.rs
+++ b/rust/trezor-client/src/messages/generated.rs
@@ -203,6 +203,8 @@ trezor_message_impl! {
EvoluRegistrationRequest => MessageType_EvoluRegistrationRequest,
EvoluGetDelegatedIdentityKey => MessageType_EvoluGetDelegatedIdentityKey,
EvoluDelegatedIdentityKey => MessageType_EvoluDelegatedIdentityKey,
+ EvoluIndexManagement => MessageType_EvoluIndexManagement,
+ EvoluIndexManagementResponse => MessageType_EvoluIndexManagementResponse,
}
#[cfg(feature = "monero")]
diff --git a/rust/trezor-client/src/protos/generated/messages.rs b/rust/trezor-client/src/protos/generated/messages.rs
index b445c6b3..83a88cf9 100644
--- a/rust/trezor-client/src/protos/generated/messages.rs
+++ b/rust/trezor-client/src/protos/generated/messages.rs
@@ -555,6 +555,10 @@ pub enum MessageType {
MessageType_EvoluGetDelegatedIdentityKey = 2104,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_EvoluDelegatedIdentityKey)
MessageType_EvoluDelegatedIdentityKey = 2105,
+ // @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_EvoluIndexManagement)
+ MessageType_EvoluIndexManagement = 2106,
+ // @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_EvoluIndexManagementResponse)
+ MessageType_EvoluIndexManagementResponse = 2107,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_TronGetAddress)
MessageType_TronGetAddress = 2200,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_TronAddress)
@@ -864,6 +868,8 @@ impl ::protobuf::Enum for MessageType {
2103 => ::std::option::Option::Some(MessageType::MessageType_EvoluRegistrationRequest),
2104 => ::std::option::Option::Some(MessageType::MessageType_EvoluGetDelegatedIdentityKey),
2105 => ::std::option::Option::Some(MessageType::MessageType_EvoluDelegatedIdentityKey),
+ 2106 => ::std::option::Option::Some(MessageType::MessageType_EvoluIndexManagement),
+ 2107 => ::std::option::Option::Some(MessageType::MessageType_EvoluIndexManagementResponse),
2200 => ::std::option::Option::Some(MessageType::MessageType_TronGetAddress),
2201 => ::std::option::Option::Some(MessageType::MessageType_TronAddress),
2202 => ::std::option::Option::Some(MessageType::MessageType_TronSignTx),
@@ -1151,6 +1157,8 @@ impl ::protobuf::Enum for MessageType {
"MessageType_EvoluRegistrationRequest" => ::std::option::Option::Some(MessageType::MessageType_EvoluRegistrationRequest),
"MessageType_EvoluGetDelegatedIdentityKey" => ::std::option::Option::Some(MessageType::MessageType_EvoluGetDelegatedIdentityKey),
"MessageType_EvoluDelegatedIdentityKey" => ::std::option::Option::Some(MessageType::MessageType_EvoluDelegatedIdentityKey),
+ "MessageType_EvoluIndexManagement" => ::std::option::Option::Some(MessageType::MessageType_EvoluIndexManagement),
+ "MessageType_EvoluIndexManagementResponse" => ::std::option::Option::Some(MessageType::MessageType_EvoluIndexManagementResponse),
"MessageType_TronGetAddress" => ::std::option::Option::Some(MessageType::MessageType_TronGetAddress),
"MessageType_TronAddress" => ::std::option::Option::Some(MessageType::MessageType_TronAddress),
"MessageType_TronSignTx" => ::std::option::Option::Some(MessageType::MessageType_TronSignTx),
@@ -1437,6 +1445,8 @@ impl ::protobuf::Enum for MessageType {
MessageType::MessageType_EvoluRegistrationRequest,
MessageType::MessageType_EvoluGetDelegatedIdentityKey,
MessageType::MessageType_EvoluDelegatedIdentityKey,
+ MessageType::MessageType_EvoluIndexManagement,
+ MessageType::MessageType_EvoluIndexManagementResponse,
MessageType::MessageType_TronGetAddress,
MessageType::MessageType_TronAddress,
MessageType::MessageType_TronSignTx,
@@ -1729,23 +1739,25 @@ impl ::protobuf::EnumFull for MessageType {
MessageType::MessageType_EvoluRegistrationRequest => 261,
MessageType::MessageType_EvoluGetDelegatedIdentityKey => 262,
MessageType::MessageType_EvoluDelegatedIdentityKey => 263,
- MessageType::MessageType_TronGetAddress => 264,
- MessageType::MessageType_TronAddress => 265,
- MessageType::MessageType_TronSignTx => 266,
- MessageType::MessageType_TronSignature => 267,
- MessageType::MessageType_TronContractRequest => 268,
- MessageType::MessageType_TronTransferContract => 269,
- MessageType::MessageType_TronTriggerSmartContract => 270,
- MessageType::MessageType_TronFreezeBalanceV2Contract => 271,
- MessageType::MessageType_TronUnfreezeBalanceV2Contract => 272,
- MessageType::MessageType_TronWithdrawUnfreeze => 273,
- MessageType::MessageType_TronVoteWitnessContract => 274,
- MessageType::MessageType_BenchmarkListNames => 275,
- MessageType::MessageType_BenchmarkNames => 276,
- MessageType::MessageType_BenchmarkRun => 277,
- MessageType::MessageType_BenchmarkResult => 278,
- MessageType::MessageType_TelemetryGet => 279,
- MessageType::MessageType_Telemetry => 280,
+ MessageType::MessageType_EvoluIndexManagement => 264,
+ MessageType::MessageType_EvoluIndexManagementResponse => 265,
+ MessageType::MessageType_TronGetAddress => 266,
+ MessageType::MessageType_TronAddress => 267,
+ MessageType::MessageType_TronSignTx => 268,
+ MessageType::MessageType_TronSignature => 269,
+ MessageType::MessageType_TronContractRequest => 270,
+ MessageType::MessageType_TronTransferContract => 271,
+ MessageType::MessageType_TronTriggerSmartContract => 272,
+ MessageType::MessageType_TronFreezeBalanceV2Contract => 273,
+ MessageType::MessageType_TronUnfreezeBalanceV2Contract => 274,
+ MessageType::MessageType_TronWithdrawUnfreeze => 275,
+ MessageType::MessageType_TronVoteWitnessContract => 276,
+ MessageType::MessageType_BenchmarkListNames => 277,
+ MessageType::MessageType_BenchmarkNames => 278,
+ MessageType::MessageType_BenchmarkRun => 279,
+ MessageType::MessageType_BenchmarkResult => 280,
+ MessageType::MessageType_TelemetryGet => 281,
+ MessageType::MessageType_Telemetry => 282,
};
Self::enum_descriptor().value_by_index(index)
}
@@ -1764,7 +1776,7 @@ impl MessageType {
}
static file_descriptor_proto_data: &'static [u8] = b"\
- \n\x0emessages.proto\x12\x12hw.trezor.messages\x1a\roptions.proto*\xb3b\
+ \n\x0emessages.proto\x12\x12hw.trezor.messages\x1a\roptions.proto*\x9dc\
\n\x0bMessageType\x12(\n\x16MessageType_Initialize\x10\0\x1a\x0c\x80\xa6\
\x1d\x01\xb0\xb5\x18\x01\x90\xb5\x18\x01\x12\x1e\n\x10MessageType_Ping\
\x10\x01\x1a\x08\x80\xa6\x1d\x01\x90\xb5\x18\x01\x12%\n\x13MessageType_S\
@@ -2067,31 +2079,34 @@ static file_descriptor_proto_data: &'static [u8] = b"\
ageType_EvoluRegistrationRequest\x10\xb7\x10\x1a\x08\x80\xa6\x1d\x01\x98\
\xb5\x18\x01\x127\n(MessageType_EvoluGetDelegatedIdentityKey\x10\xb8\x10\
\x1a\x08\x80\xa6\x1d\x01\x90\xb5\x18\x01\x124\n%MessageType_EvoluDelegat\
- edIdentityKey\x10\xb9\x10\x1a\x08\x80\xa6\x1d\x01\x98\xb5\x18\x01\x12%\n\
- \x1aMessageType_TronGetAddress\x10\x98\x11\x1a\x04\x90\xb5\x18\x01\x12\"\
- \n\x17MessageType_TronAddress\x10\x99\x11\x1a\x04\x98\xb5\x18\x01\x12!\n\
- \x16MessageType_TronSignTx\x10\x9a\x11\x1a\x04\x90\xb5\x18\x01\x12$\n\
- \x19MessageType_TronSignature\x10\x9b\x11\x1a\x04\x98\xb5\x18\x01\x12*\n\
- \x1fMessageType_TronContractRequest\x10\x9c\x11\x1a\x04\x98\xb5\x18\x01\
- \x12+\n\x20MessageType_TronTransferContract\x10\x9d\x11\x1a\x04\x90\xb5\
- \x18\x01\x12/\n$MessageType_TronTriggerSmartContract\x10\x9e\x11\x1a\x04\
- \x90\xb5\x18\x01\x122\n'MessageType_TronFreezeBalanceV2Contract\x10\x9f\
- \x11\x1a\x04\x90\xb5\x18\x01\x124\n)MessageType_TronUnfreezeBalanceV2Con\
- tract\x10\xa0\x11\x1a\x04\x90\xb5\x18\x01\x12+\n\x20MessageType_TronWith\
- drawUnfreeze\x10\xa1\x11\x1a\x04\x90\xb5\x18\x01\x12.\n#MessageType_Tron\
- VoteWitnessContract\x10\xa2\x11\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMessag\
- eType_BenchmarkListNames\x10\x8cG\x1a\x04\x80\xa6\x1d\x01\x12%\n\x1aMess\
- ageType_BenchmarkNames\x10\x8dG\x1a\x04\x80\xa6\x1d\x01\x12#\n\x18Messag\
- eType_BenchmarkRun\x10\x8eG\x1a\x04\x80\xa6\x1d\x01\x12&\n\x1bMessageTyp\
- e_BenchmarkResult\x10\x8fG\x1a\x04\x80\xa6\x1d\x01\x12'\n\x18MessageType\
- _TelemetryGet\x10\xcc\x08\x1a\x08\x80\xa6\x1d\x01\x90\xb5\x18\x01\x12$\n\
- \x15MessageType_Telemetry\x10\xcd\x08\x1a\x08\x80\xa6\x1d\x01\x98\xb5\
- \x18\x01\x1a\x08\xc8\xf3\x18\x01\xd0\xf3\x18\x01\"\x04\x08Z\x10\\\"\x04\
- \x08G\x10J\"\x04\x08r\x10z\"\x05\x08{\x10\x95\x01\"\x06\x08\xdb\x01\x10\
- \xdb\x01\"\x06\x08\xe0\x01\x10\xe0\x01\"\x06\x08\xac\x02\x10\xb0\x02\"\
- \x06\x08\xb5\x02\x10\xb8\x02\"\x06\x08\xbc\x05\x10\xc5\x05\"\x06\x08\xe9\
- \x07\x10\xf7\x07\"\x06\x08\xfa\x07\x10\xcb\x08B8\n#com.satoshilabs.trezo\
- r.lib.protobufB\rTrezorMessage\x80\xa6\x1d\x01\
+ edIdentityKey\x10\xb9\x10\x1a\x08\x80\xa6\x1d\x01\x98\xb5\x18\x01\x12/\n\
+ \x20MessageType_EvoluIndexManagement\x10\xba\x10\x1a\x08\x80\xa6\x1d\x01\
+ \x90\xb5\x18\x01\x127\n(MessageType_EvoluIndexManagementResponse\x10\xbb\
+ \x10\x1a\x08\x80\xa6\x1d\x01\x98\xb5\x18\x01\x12%\n\x1aMessageType_TronG\
+ etAddress\x10\x98\x11\x1a\x04\x90\xb5\x18\x01\x12\"\n\x17MessageType_Tro\
+ nAddress\x10\x99\x11\x1a\x04\x98\xb5\x18\x01\x12!\n\x16MessageType_TronS\
+ ignTx\x10\x9a\x11\x1a\x04\x90\xb5\x18\x01\x12$\n\x19MessageType_TronSign\
+ ature\x10\x9b\x11\x1a\x04\x98\xb5\x18\x01\x12*\n\x1fMessageType_TronCont\
+ ractRequest\x10\x9c\x11\x1a\x04\x98\xb5\x18\x01\x12+\n\x20MessageType_Tr\
+ onTransferContract\x10\x9d\x11\x1a\x04\x90\xb5\x18\x01\x12/\n$MessageTyp\
+ e_TronTriggerSmartContract\x10\x9e\x11\x1a\x04\x90\xb5\x18\x01\x122\n'Me\
+ ssageType_TronFreezeBalanceV2Contract\x10\x9f\x11\x1a\x04\x90\xb5\x18\
+ \x01\x124\n)MessageType_TronUnfreezeBalanceV2Contract\x10\xa0\x11\x1a\
+ \x04\x90\xb5\x18\x01\x12+\n\x20MessageType_TronWithdrawUnfreeze\x10\xa1\
+ \x11\x1a\x04\x90\xb5\x18\x01\x12.\n#MessageType_TronVoteWitnessContract\
+ \x10\xa2\x11\x1a\x04\x90\xb5\x18\x01\x12)\n\x1eMessageType_BenchmarkList\
+ Names\x10\x8cG\x1a\x04\x80\xa6\x1d\x01\x12%\n\x1aMessageType_BenchmarkNa\
+ mes\x10\x8dG\x1a\x04\x80\xa6\x1d\x01\x12#\n\x18MessageType_BenchmarkRun\
+ \x10\x8eG\x1a\x04\x80\xa6\x1d\x01\x12&\n\x1bMessageType_BenchmarkResult\
+ \x10\x8fG\x1a\x04\x80\xa6\x1d\x01\x12'\n\x18MessageType_TelemetryGet\x10\
+ \xcc\x08\x1a\x08\x80\xa6\x1d\x01\x90\xb5\x18\x01\x12$\n\x15MessageType_T\
+ elemetry\x10\xcd\x08\x1a\x08\x80\xa6\x1d\x01\x98\xb5\x18\x01\x1a\x08\xc8\
+ \xf3\x18\x01\xd0\xf3\x18\x01\"\x04\x08Z\x10\\\"\x04\x08G\x10J\"\x04\x08r\
+ \x10z\"\x05\x08{\x10\x95\x01\"\x06\x08\xdb\x01\x10\xdb\x01\"\x06\x08\xe0\
+ \x01\x10\xe0\x01\"\x06\x08\xac\x02\x10\xb0\x02\"\x06\x08\xb5\x02\x10\xb8\
+ \x02\"\x06\x08\xbc\x05\x10\xc5\x05\"\x06\x08\xe9\x07\x10\xf7\x07\"\x06\
+ \x08\xfa\x07\x10\xcb\x08B8\n#com.satoshilabs.trezor.lib.protobufB\rTrezo\
+ rMessage\x80\xa6\x1d\x01\
";
/// `FileDescriptorProto` object which was a source for this generated file
diff --git a/rust/trezor-client/src/protos/generated/messages_evolu.rs b/rust/trezor-client/src/protos/generated/messages_evolu.rs
index 853897b4..b91f9b21 100644
--- a/rust/trezor-client/src/protos/generated/messages_evolu.rs
+++ b/rust/trezor-client/src/protos/generated/messages_evolu.rs
@@ -30,6 +30,8 @@ pub struct EvoluGetNode {
// message fields
// @@protoc_insertion_point(field:hw.trezor.messages.evolu.EvoluGetNode.proof_of_delegated_identity)
pub proof_of_delegated_identity: ::std::option::Option<::std::vec::Vec<u8>>,
+ // @@protoc_insertion_point(field:hw.trezor.messages.evolu.EvoluGetNode.node_rotation_index)
+ pub node_rotation_index: ::std::option::Option<u32>,
// special fields
// @@protoc_insertion_point(special_field:hw.trezor.messages.evolu.EvoluGetNode.special_fields)
pub special_fields: ::protobuf::SpecialFields,
@@ -82,14 +84,38 @@ impl EvoluGetNode {
self.proof_of_delegated_identity.take().unwrap_or_else(|| ::std::vec::Vec::new())
}
+ // optional uint32 node_rotation_index = 2;
+
+ pub fn node_rotation_index(&self) -> u32 {
+ self.node_rotation_index.unwrap_or(0u32)
+ }
+
+ pub fn clear_node_rotation_index(&mut self) {
+ self.node_rotation_index = ::std::option::Option::None;
+ }
+
+ pub fn has_node_rotation_index(&self) -> bool {
+ self.node_rotation_index.is_some()
+ }
+
+ // Param is passed by value, moved
+ pub fn set_node_rotation_index(&mut self, v: u32) {
+ self.node_rotation_index = ::std::option::Option::Some(v);
+ }
+
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
- let mut fields = ::std::vec::Vec::with_capacity(1);
+ let mut fields = ::std::vec::Vec::with_capacity(2);
let mut oneofs = ::std::vec::Vec::with_capacity(0);
fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
"proof_of_delegated_identity",
|m: &EvoluGetNode| { &m.proof_of_delegated_identity },
|m: &mut EvoluGetNode| { &mut m.proof_of_delegated_identity },
));
+ fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
+ "node_rotation_index",
+ |m: &EvoluGetNode| { &m.node_rotation_index },
+ |m: &mut EvoluGetNode| { &mut m.node_rotation_index },
+ ));
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<EvoluGetNode>(
"EvoluGetNode",
fields,
@@ -114,6 +140,9 @@ impl ::protobuf::Message for EvoluGetNode {
10 => {
self.proof_of_delegated_identity = ::std::option::Option::Some(is.read_bytes()?);
},
+ 16 => {
+ self.node_rotation_index = ::std::option::Option::Some(is.read_uint32()?);
+ },
tag => {
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
},
@@ -129,6 +158,9 @@ impl ::protobuf::Message for EvoluGetNode {
if let Some(v) = self.proof_of_delegated_identity.as_ref() {
my_size += ::protobuf::rt::bytes_size(1, &v);
}
+ if let Some(v) = self.node_rotation_index {
+ my_size += ::protobuf::rt::uint32_size(2, v);
+ }
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
self.special_fields.cached_size().set(my_size as u32);
my_size
@@ -138,6 +170,9 @@ impl ::protobuf::Message for EvoluGetNode {
if let Some(v) = self.proof_of_delegated_identity.as_ref() {
os.write_bytes(1, v)?;
}
+ if let Some(v) = self.node_rotation_index {
+ os.write_uint32(2, v)?;
+ }
os.write_unknown_fields(self.special_fields.unknown_fields())?;
::std::result::Result::Ok(())
}
@@ -156,12 +191,14 @@ impl ::protobuf::Message for EvoluGetNode {
fn clear(&mut self) {
self.proof_of_delegated_identity = ::std::option::Option::None;
+ self.node_rotation_index = ::std::option::Option::None;
self.special_fields.clear();
}
fn default_instance() -> &'static EvoluGetNode {
static instance: EvoluGetNode = EvoluGetNode {
proof_of_delegated_identity: ::std::option::Option::None,
+ node_rotation_index: ::std::option::Option::None,
special_fields: ::protobuf::SpecialFields::new(),
};
&instance
@@ -789,6 +826,10 @@ pub struct EvoluGetDelegatedIdentityKey {
// message fields
// @@protoc_insertion_point(field:hw.trezor.messages.evolu.EvoluGetDelegatedIdentityKey.thp_credential)
pub thp_credential: ::std::option::Option<::std::vec::Vec<u8>>,
+ // @@protoc_insertion_point(field:hw.trezor.messages.evolu.EvoluGetDelegatedIdentityKey.rotation_index)
+ pub rotation_index: ::std::option::Option<u32>,
+ // @@protoc_insertion_point(field:hw.trezor.messages.evolu.EvoluGetDelegatedIdentityKey.rotate)
+ pub rotate: ::std::option::Option<bool>,
// special fields
// @@protoc_insertion_point(special_field:hw.trezor.messages.evolu.EvoluGetDelegatedIdentityKey.special_fields)
pub special_fields: ::protobuf::SpecialFields,
@@ -841,14 +882,62 @@ impl EvoluGetDelegatedIdentityKey {
self.thp_credential.take().unwrap_or_else(|| ::std::vec::Vec::new())
}
+ // optional uint32 rotation_index = 3;
+
+ pub fn rotation_index(&self) -> u32 {
+ self.rotation_index.unwrap_or(0)
+ }
+
+ pub fn clear_rotation_index(&mut self) {
+ self.rotation_index = ::std::option::Option::None;
+ }
+
+ pub fn has_rotation_index(&self) -> bool {
+ self.rotation_index.is_some()
+ }
+
+ // Param is passed by value, moved
+ pub fn set_rotation_index(&mut self, v: u32) {
+ self.rotation_index = ::std::option::Option::Some(v);
+ }
+
+ // optional bool rotate = 4;
+
+ pub fn rotate(&self) -> bool {
+ self.rotate.unwrap_or(false)
+ }
+
+ pub fn clear_rotate(&mut self) {
+ self.rotate = ::std::option::Option::None;
+ }
+
+ pub fn has_rotate(&self) -> bool {
+ self.rotate.is_some()
+ }
+
+ // Param is passed by value, moved
+ pub fn set_rotate(&mut self, v: bool) {
+ self.rotate = ::std::option::Option::Some(v);
+ }
+
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
- let mut fields = ::std::vec::Vec::with_capacity(1);
+ let mut fields = ::std::vec::Vec::with_capacity(3);
let mut oneofs = ::std::vec::Vec::with_capacity(0);
fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
"thp_credential",
|m: &EvoluGetDelegatedIdentityKey| { &m.thp_credential },
|m: &mut EvoluGetDelegatedIdentityKey| { &mut m.thp_credential },
));
+ fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
+ "rotation_index",
+ |m: &EvoluGetDelegatedIdentityKey| { &m.rotation_index },
+ |m: &mut EvoluGetDelegatedIdentityKey| { &mut m.rotation_index },
+ ));
+ fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
+ "rotate",
+ |m: &EvoluGetDelegatedIdentityKey| { &m.rotate },
+ |m: &mut EvoluGetDelegatedIdentityKey| { &mut m.rotate },
+ ));
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<EvoluGetDelegatedIdentityKey>(
"EvoluGetDelegatedIdentityKey",
fields,
@@ -870,6 +959,12 @@ impl ::protobuf::Message for EvoluGetDelegatedIdentityKey {
10 => {
self.thp_credential = ::std::option::Option::Some(is.read_bytes()?);
},
+ 24 => {
+ self.rotation_index = ::std::option::Option::Some(is.read_uint32()?);
+ },
+ 32 => {
+ self.rotate = ::std::option::Option::Some(is.read_bool()?);
+ },
tag => {
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
},
@@ -885,6 +980,12 @@ impl ::protobuf::Message for EvoluGetDelegatedIdentityKey {
if let Some(v) = self.thp_credential.as_ref() {
my_size += ::protobuf::rt::bytes_size(1, &v);
}
+ if let Some(v) = self.rotation_index {
+ my_size += ::protobuf::rt::uint32_size(3, v);
+ }
+ if let Some(v) = self.rotate {
+ my_size += 1 + 1;
+ }
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
self.special_fields.cached_size().set(my_size as u32);
my_size
@@ -894,6 +995,12 @@ impl ::protobuf::Message for EvoluGetDelegatedIdentityKey {
if let Some(v) = self.thp_credential.as_ref() {
os.write_bytes(1, v)?;
}
+ if let Some(v) = self.rotation_index {
+ os.write_uint32(3, v)?;
+ }
+ if let Some(v) = self.rotate {
+ os.write_bool(4, v)?;
+ }
os.write_unknown_fields(self.special_fields.unknown_fields())?;
::std::result::Result::Ok(())
}
@@ -912,12 +1019,16 @@ impl ::protobuf::Message for EvoluGetDelegatedIdentityKey {
fn clear(&mut self) {
self.thp_credential = ::std::option::Option::None;
+ self.rotation_index = ::std::option::Option::None;
+ self.rotate = ::std::option::Option::None;
self.special_fields.clear();
}
fn default_instance() -> &'static EvoluGetDelegatedIdentityKey {
static instance: EvoluGetDelegatedIdentityKey = EvoluGetDelegatedIdentityKey {
thp_credential: ::std::option::Option::None,
+ rotation_index: ::std::option::Option::None,
+ rotate: ::std::option::Option::None,
special_fields: ::protobuf::SpecialFields::new(),
};
&instance
@@ -947,6 +1058,8 @@ pub struct EvoluDelegatedIdentityKey {
// message fields
// @@protoc_insertion_point(field:hw.trezor.messages.evolu.EvoluDelegatedIdentityKey.private_key)
pub private_key: ::std::option::Option<::std::vec::Vec<u8>>,
+ // @@protoc_insertion_point(field:hw.trezor.messages.evolu.EvoluDelegatedIdentityKey.rotation_index)
+ pub rotation_index: ::std::option::Option<u32>,
// special fields
// @@protoc_insertion_point(special_field:hw.trezor.messages.evolu.EvoluDelegatedIdentityKey.special_fields)
pub special_fields: ::protobuf::SpecialFields,
@@ -999,14 +1112,38 @@ impl EvoluDelegatedIdentityKey {
self.private_key.take().unwrap_or_else(|| ::std::vec::Vec::new())
}
+ // optional uint32 rotation_index = 2;
+
+ pub fn rotation_index(&self) -> u32 {
+ self.rotation_index.unwrap_or(0)
+ }
+
+ pub fn clear_rotation_index(&mut self) {
+ self.rotation_index = ::std::option::Option::None;
+ }
+
+ pub fn has_rotation_index(&self) -> bool {
+ self.rotation_index.is_some()
+ }
+
+ // Param is passed by value, moved
+ pub fn set_rotation_index(&mut self, v: u32) {
+ self.rotation_index = ::std::option::Option::Some(v);
+ }
+
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
- let mut fields = ::std::vec::Vec::with_capacity(1);
+ let mut fields = ::std::vec::Vec::with_capacity(2);
let mut oneofs = ::std::vec::Vec::with_capacity(0);
fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
"private_key",
|m: &EvoluDelegatedIdentityKey| { &m.private_key },
|m: &mut EvoluDelegatedIdentityKey| { &mut m.private_key },
));
+ fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
+ "rotation_index",
+ |m: &EvoluDelegatedIdentityKey| { &m.rotation_index },
+ |m: &mut EvoluDelegatedIdentityKey| { &mut m.rotation_index },
+ ));
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<EvoluDelegatedIdentityKey>(
"EvoluDelegatedIdentityKey",
fields,
@@ -1031,6 +1168,9 @@ impl ::protobuf::Message for EvoluDelegatedIdentityKey {
10 => {
self.private_key = ::std::option::Option::Some(is.read_bytes()?);
},
+ 16 => {
+ self.rotation_index = ::std::option::Option::Some(is.read_uint32()?);
+ },
tag => {
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
},
@@ -1046,6 +1186,9 @@ impl ::protobuf::Message for EvoluDelegatedIdentityKey {
if let Some(v) = self.private_key.as_ref() {
my_size += ::protobuf::rt::bytes_size(1, &v);
}
+ if let Some(v) = self.rotation_index {
+ my_size += ::protobuf::rt::uint32_size(2, v);
+ }
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
self.special_fields.cached_size().set(my_size as u32);
my_size
@@ -1055,6 +1198,9 @@ impl ::protobuf::Message for EvoluDelegatedIdentityKey {
if let Some(v) = self.private_key.as_ref() {
os.write_bytes(1, v)?;
}
+ if let Some(v) = self.rotation_index {
+ os.write_uint32(2, v)?;
+ }
os.write_unknown_fields(self.special_fields.unknown_fields())?;
::std::result::Result::Ok(())
}
@@ -1073,12 +1219,14 @@ impl ::protobuf::Message for EvoluDelegatedIdentityKey {
fn clear(&mut self) {
self.private_key = ::std::option::Option::None;
+ self.rotation_index = ::std::option::Option::None;
self.special_fields.clear();
}
fn default_instance() -> &'static EvoluDelegatedIdentityKey {
static instance: EvoluDelegatedIdentityKey = EvoluDelegatedIdentityKey {
private_key: ::std::option::Option::None,
+ rotation_index: ::std::option::Option::None,
special_fields: ::protobuf::SpecialFields::new(),
};
&instance
@@ -1102,21 +1250,309 @@ impl ::protobuf::reflect::ProtobufValue for EvoluDelegatedIdentityKey {
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
}
+// @@protoc_insertion_point(message:hw.trezor.messages.evolu.EvoluIndexManagement)
+#[derive(PartialEq,Clone,Default,Debug)]
+pub struct EvoluIndexManagement {
+ // message fields
+ // @@protoc_insertion_point(field:hw.trezor.messages.evolu.EvoluIndexManagement.rotation_index)
+ pub rotation_index: ::std::option::Option<u32>,
+ // special fields
+ // @@protoc_insertion_point(special_field:hw.trezor.messages.evolu.EvoluIndexManagement.special_fields)
+ pub special_fields: ::protobuf::SpecialFields,
+}
+
+impl<'a> ::std::default::Default for &'a EvoluIndexManagement {
+ fn default() -> &'a EvoluIndexManagement {
+ <EvoluIndexManagement as ::protobuf::Message>::default_instance()
+ }
+}
+
+impl EvoluIndexManagement {
+ pub fn new() -> EvoluIndexManagement {
+ ::std::default::Default::default()
+ }
+
+ // optional uint32 rotation_index = 1;
+
+ pub fn rotation_index(&self) -> u32 {
+ self.rotation_index.unwrap_or(0)
+ }
+
+ pub fn clear_rotation_index(&mut self) {
+ self.rotation_index = ::std::option::Option::None;
+ }
+
+ pub fn has_rotation_index(&self) -> bool {
+ self.rotation_index.is_some()
+ }
+
+ // Param is passed by value, moved
+ pub fn set_rotation_index(&mut self, v: u32) {
+ self.rotation_index = ::std::option::Option::Some(v);
+ }
+
+ fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
+ let mut fields = ::std::vec::Vec::with_capacity(1);
+ let mut oneofs = ::std::vec::Vec::with_capacity(0);
+ fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
+ "rotation_index",
+ |m: &EvoluIndexManagement| { &m.rotation_index },
+ |m: &mut EvoluIndexManagement| { &mut m.rotation_index },
+ ));
+ ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<EvoluIndexManagement>(
+ "EvoluIndexManagement",
+ fields,
+ oneofs,
+ )
+ }
+}
+
+impl ::protobuf::Message for EvoluIndexManagement {
+ const NAME: &'static str = "EvoluIndexManagement";
+
+ fn is_initialized(&self) -> bool {
+ true
+ }
+
+ fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+ while let Some(tag) = is.read_raw_tag_or_eof()? {
+ match tag {
+ 8 => {
+ self.rotation_index = ::std::option::Option::Some(is.read_uint32()?);
+ },
+ tag => {
+ ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
+ },
+ };
+ }
+ ::std::result::Result::Ok(())
+ }
+
+ // Compute sizes of nested messages
+ #[allow(unused_variables)]
+ fn compute_size(&self) -> u64 {
+ let mut my_size = 0;
+ if let Some(v) = self.rotation_index {
+ my_size += ::protobuf::rt::uint32_size(1, v);
+ }
+ my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+ self.special_fields.cached_size().set(my_size as u32);
+ my_size
+ }
+
+ fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
+ if let Some(v) = self.rotation_index {
+ os.write_uint32(1, v)?;
+ }
+ os.write_unknown_fields(self.special_fields.unknown_fields())?;
+ ::std::result::Result::Ok(())
+ }
+
+ fn special_fields(&self) -> &::protobuf::SpecialFields {
+ &self.special_fields
+ }
+
+ fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+ &mut self.special_fields
+ }
+
+ fn new() -> EvoluIndexManagement {
+ EvoluIndexManagement::new()
+ }
+
+ fn clear(&mut self) {
+ self.rotation_index = ::std::option::Option::None;
+ self.special_fields.clear();
+ }
+
+ fn default_instance() -> &'static EvoluIndexManagement {
+ static instance: EvoluIndexManagement = EvoluIndexManagement {
+ rotation_index: ::std::option::Option::None,
+ special_fields: ::protobuf::SpecialFields::new(),
+ };
+ &instance
+ }
+}
+
+impl ::protobuf::MessageFull for EvoluIndexManagement {
+ fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
+ static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
+ descriptor.get(|| file_descriptor().message_by_package_relative_name("EvoluIndexManagement").unwrap()).clone()
+ }
+}
+
+impl ::std::fmt::Display for EvoluIndexManagement {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+ ::protobuf::text_format::fmt(self, f)
+ }
+}
+
+impl ::protobuf::reflect::ProtobufValue for EvoluIndexManagement {
+ type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
+}
+
+// @@protoc_insertion_point(message:hw.trezor.messages.evolu.EvoluIndexManagementResponse)
+#[derive(PartialEq,Clone,Default,Debug)]
+pub struct EvoluIndexManagementResponse {
+ // message fields
+ // @@protoc_insertion_point(field:hw.trezor.messages.evolu.EvoluIndexManagementResponse.rotation_index)
+ pub rotation_index: ::std::option::Option<u32>,
+ // special fields
+ // @@protoc_insertion_point(special_field:hw.trezor.messages.evolu.EvoluIndexManagementResponse.special_fields)
+ pub special_fields: ::protobuf::SpecialFields,
+}
+
+impl<'a> ::std::default::Default for &'a EvoluIndexManagementResponse {
+ fn default() -> &'a EvoluIndexManagementResponse {
+ <EvoluIndexManagementResponse as ::protobuf::Message>::default_instance()
+ }
+}
+
+impl EvoluIndexManagementResponse {
+ pub fn new() -> EvoluIndexManagementResponse {
+ ::std::default::Default::default()
+ }
+
+ // optional uint32 rotation_index = 1;
+
+ pub fn rotation_index(&self) -> u32 {
+ self.rotation_index.unwrap_or(0)
+ }
+
+ pub fn clear_rotation_index(&mut self) {
+ self.rotation_index = ::std::option::Option::None;
+ }
+
+ pub fn has_rotation_index(&self) -> bool {
+ self.rotation_index.is_some()
+ }
+
+ // Param is passed by value, moved
+ pub fn set_rotation_index(&mut self, v: u32) {
+ self.rotation_index = ::std::option::Option::Some(v);
+ }
+
+ fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
+ let mut fields = ::std::vec::Vec::with_capacity(1);
+ let mut oneofs = ::std::vec::Vec::with_capacity(0);
+ fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
+ "rotation_index",
+ |m: &EvoluIndexManagementResponse| { &m.rotation_index },
+ |m: &mut EvoluIndexManagementResponse| { &mut m.rotation_index },
+ ));
+ ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<EvoluIndexManagementResponse>(
+ "EvoluIndexManagementResponse",
+ fields,
+ oneofs,
+ )
+ }
+}
+
+impl ::protobuf::Message for EvoluIndexManagementResponse {
+ const NAME: &'static str = "EvoluIndexManagementResponse";
+
+ fn is_initialized(&self) -> bool {
+ true
+ }
+
+ fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
+ while let Some(tag) = is.read_raw_tag_or_eof()? {
+ match tag {
+ 8 => {
+ self.rotation_index = ::std::option::Option::Some(is.read_uint32()?);
+ },
+ tag => {
+ ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
+ },
+ };
+ }
+ ::std::result::Result::Ok(())
+ }
+
+ // Compute sizes of nested messages
+ #[allow(unused_variables)]
+ fn compute_size(&self) -> u64 {
+ let mut my_size = 0;
+ if let Some(v) = self.rotation_index {
+ my_size += ::protobuf::rt::uint32_size(1, v);
+ }
+ my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
+ self.special_fields.cached_size().set(my_size as u32);
+ my_size
+ }
+
+ fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
+ if let Some(v) = self.rotation_index {
+ os.write_uint32(1, v)?;
+ }
+ os.write_unknown_fields(self.special_fields.unknown_fields())?;
+ ::std::result::Result::Ok(())
+ }
+
+ fn special_fields(&self) -> &::protobuf::SpecialFields {
+ &self.special_fields
+ }
+
+ fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
+ &mut self.special_fields
+ }
+
+ fn new() -> EvoluIndexManagementResponse {
+ EvoluIndexManagementResponse::new()
+ }
+
+ fn clear(&mut self) {
+ self.rotation_index = ::std::option::Option::None;
+ self.special_fields.clear();
+ }
+
+ fn default_instance() -> &'static EvoluIndexManagementResponse {
+ static instance: EvoluIndexManagementResponse = EvoluIndexManagementResponse {
+ rotation_index: ::std::option::Option::None,
+ special_fields: ::protobuf::SpecialFields::new(),
+ };
+ &instance
+ }
+}
+
+impl ::protobuf::MessageFull for EvoluIndexManagementResponse {
+ fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
+ static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
+ descriptor.get(|| file_descriptor().message_by_package_relative_name("EvoluIndexManagementResponse").unwrap()).clone()
+ }
+}
+
+impl ::std::fmt::Display for EvoluIndexManagementResponse {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+ ::protobuf::text_format::fmt(self, f)
+ }
+}
+
+impl ::protobuf::reflect::ProtobufValue for EvoluIndexManagementResponse {
+ type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
+}
+
static file_descriptor_proto_data: &'static [u8] = b"\
\n\x14messages-evolu.proto\x12\x18hw.trezor.messages.evolu\x1a\roptions.\
- proto\"M\n\x0cEvoluGetNode\x12=\n\x1bproof_of_delegated_identity\x18\x01\
- \x20\x02(\x0cR\x18proofOfDelegatedIdentity\"\x1f\n\tEvoluNode\x12\x12\n\
- \x04data\x18\x01\x20\x02(\x0cR\x04data\"\xb9\x01\n\x1cEvoluSignRegistrat\
- ionRequest\x122\n\x15challenge_from_server\x18\x01\x20\x02(\x0cR\x13chal\
- lengeFromServer\x12&\n\x0fsize_to_acquire\x18\x02\x20\x02(\rR\rsizeToAcq\
- uire\x12=\n\x1bproof_of_delegated_identity\x18\x03\x20\x02(\x0cR\x18proo\
- fOfDelegatedIdentity\"e\n\x18EvoluRegistrationRequest\x12+\n\x11certific\
- ate_chain\x18\x01\x20\x03(\x0cR\x10certificateChain\x12\x1c\n\tsignature\
- \x18\x02\x20\x02(\x0cR\tsignature\"K\n\x1cEvoluGetDelegatedIdentityKey\
- \x12%\n\x0ethp_credential\x18\x01\x20\x01(\x0cR\rthpCredentialJ\x04\x08\
- \x02\x10\x03\"<\n\x19EvoluDelegatedIdentityKey\x12\x1f\n\x0bprivate_key\
- \x18\x01\x20\x02(\x0cR\nprivateKeyB=\n#com.satoshilabs.trezor.lib.protob\
- ufB\x12TrezorMessageEvolu\x80\xa6\x1d\x01\
+ proto\"\x80\x01\n\x0cEvoluGetNode\x12=\n\x1bproof_of_delegated_identity\
+ \x18\x01\x20\x02(\x0cR\x18proofOfDelegatedIdentity\x121\n\x13node_rotati\
+ on_index\x18\x02\x20\x01(\r:\x010R\x11nodeRotationIndex\"\x1f\n\tEvoluNo\
+ de\x12\x12\n\x04data\x18\x01\x20\x02(\x0cR\x04data\"\xb9\x01\n\x1cEvoluS\
+ ignRegistrationRequest\x122\n\x15challenge_from_server\x18\x01\x20\x02(\
+ \x0cR\x13challengeFromServer\x12&\n\x0fsize_to_acquire\x18\x02\x20\x02(\
+ \rR\rsizeToAcquire\x12=\n\x1bproof_of_delegated_identity\x18\x03\x20\x02\
+ (\x0cR\x18proofOfDelegatedIdentity\"e\n\x18EvoluRegistrationRequest\x12+\
+ \n\x11certificate_chain\x18\x01\x20\x03(\x0cR\x10certificateChain\x12\
+ \x1c\n\tsignature\x18\x02\x20\x02(\x0cR\tsignature\"\x8a\x01\n\x1cEvoluG\
+ etDelegatedIdentityKey\x12%\n\x0ethp_credential\x18\x01\x20\x01(\x0cR\rt\
+ hpCredential\x12%\n\x0erotation_index\x18\x03\x20\x01(\rR\rrotationIndex\
+ \x12\x16\n\x06rotate\x18\x04\x20\x01(\x08R\x06rotateJ\x04\x08\x02\x10\
+ \x03\"c\n\x19EvoluDelegatedIdentityKey\x12\x1f\n\x0bprivate_key\x18\x01\
+ \x20\x02(\x0cR\nprivateKey\x12%\n\x0erotation_index\x18\x02\x20\x01(\rR\
+ \rrotationIndex\"=\n\x14EvoluIndexManagement\x12%\n\x0erotation_index\
+ \x18\x01\x20\x01(\rR\rrotationIndex\"E\n\x1cEvoluIndexManagementResponse\
+ \x12%\n\x0erotation_index\x18\x01\x20\x01(\rR\rrotationIndexB=\n#com.sat\
+ oshilabs.trezor.lib.protobufB\x12TrezorMessageEvolu\x80\xa6\x1d\x01\
";
/// `FileDescriptorProto` object which was a source for this generated file
@@ -1135,13 +1571,15 @@ pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor {
let generated_file_descriptor = generated_file_descriptor_lazy.get(|| {
let mut deps = ::std::vec::Vec::with_capacity(1);
deps.push(super::options::file_descriptor().clone());
- let mut messages = ::std::vec::Vec::with_capacity(6);
+ let mut messages = ::std::vec::Vec::with_capacity(8);
messages.push(EvoluGetNode::generated_message_descriptor_data());
messages.push(EvoluNode::generated_message_descriptor_data());
messages.push(EvoluSignRegistrationRequest::generated_message_descriptor_data());
messages.push(EvoluRegistrationRequest::generated_message_descriptor_data());
messages.push(EvoluGetDelegatedIdentityKey::generated_message_descriptor_data());
messages.push(EvoluDelegatedIdentityKey::generated_message_descriptor_data());
+ messages.push(EvoluIndexManagement::generated_message_descriptor_data());
+ messages.push(EvoluIndexManagementResponse::generated_message_descriptor_data());
let mut enums = ::std::vec::Vec::with_capacity(0);
::protobuf::reflect::GeneratedFileDescriptor::new_generated(
file_descriptor_proto(),
diff --git a/tests/device_tests/evolu/common.py b/tests/device_tests/evolu/common.py
index a986be2a..38de6d69 100644
--- a/tests/device_tests/evolu/common.py
+++ b/tests/device_tests/evolu/common.py
@@ -7,7 +7,7 @@ from ecdsa import NIST256p, SigningKey
from trezorlib import evolu
from trezorlib.debuglink import DebugSession as Session
from trezorlib.debuglink import TrezorTestContext as Client
-from trezorlib.messages import ThpCredentialResponse
+from trezorlib.messages import EvoluDelegatedIdentityKey, ThpCredentialResponse
from trezorlib.thp import curve25519
from ...common import compact_size
@@ -17,8 +17,13 @@ TEST_host_static_private_key = curve25519.get_private_key(TEST_randomness)
TEST_host_static_public_key = curve25519.get_public_key(TEST_host_static_private_key)
-def get_proof(client: Client, header: bytes, arguments: List[bytes]) -> bytes:
- private_key = get_delegated_identity_key(client)
+def get_proof(
+ client: Client,
+ header: bytes,
+ arguments: List[bytes],
+ rotation_index: int | None = None,
+) -> bytes:
+ private_key = get_delegated_identity_key(client, rotation_index).private_key
signing_key = SigningKey.from_string(private_key, curve=NIST256p)
ctx = sha256()
@@ -73,14 +78,19 @@ def pair_and_get_invalid_credential(client: Client) -> ThpPairingResult:
return pairing_result
-def get_delegated_identity_key(client: Client) -> bytes:
+def get_delegated_identity_key(
+ client: Client, rotation_index: int | None = None
+) -> EvoluDelegatedIdentityKey:
if client.is_thp():
pairing_data = pair_and_get_credential(client)
return evolu.get_delegated_identity_key(
session=pairing_data.session,
thp_credential=pairing_data.credential.credential,
+ rotation_index=rotation_index,
)
elif client.is_protocol_v1():
- return evolu.get_delegated_identity_key(client.get_session())
+ return evolu.get_delegated_identity_key(
+ client.get_session(), rotation_index=rotation_index
+ )
else:
raise ValueError("Unsupported protocol version")
diff --git a/tests/device_tests/evolu/test_delegated_identity_key_rotation.py b/tests/device_tests/evolu/test_delegated_identity_key_rotation.py
new file mode 100644
index 00000000..416c4428
--- /dev/null
+++ b/tests/device_tests/evolu/test_delegated_identity_key_rotation.py
@@ -0,0 +1,173 @@
+import pytest
+
+from trezorlib import debuglink, device, evolu
+from trezorlib.debuglink import TrezorTestContext as Client
+from trezorlib.exceptions import TrezorFailure
+
+from .common import get_delegated_identity_key
+
+pytestmark = [
+ pytest.mark.models("core"),
+ # we need to start each test from the same state - wiped and freshly set seed
+ pytest.mark.setup_client(passphrase=False),
+]
+
+
+def test_first_rotation_index_is_None(client: Client):
+ response_none = evolu.index_management(client.get_session())
+ assert response_none.rotation_index is None
+
+ delegated_identity_key = get_delegated_identity_key(client)
+ assert delegated_identity_key.rotation_index is None
+
+ with pytest.raises(
+ TrezorFailure,
+ match=r"DataError: Requested rotation index \(1\) is higher than the current rotation index \(None\)",
+ ):
+ get_delegated_identity_key(client, rotation_index=1)
+
+
+def test_delegated_identity_key_rotation_index_increment(client: Client):
+ response = evolu.index_management(client.get_session(), rotation_index=2)
+ assert response.rotation_index == 2
+
+ delegated_identity_key_0 = get_delegated_identity_key(client, rotation_index=0)
+ delegated_identity_key_1 = get_delegated_identity_key(client, rotation_index=1)
+ delegated_identity_key_2 = get_delegated_identity_key(client, rotation_index=2)
+ delegated_identity_key_last = get_delegated_identity_key(client)
+
+ assert delegated_identity_key_0.rotation_index == 0
+ assert delegated_identity_key_1.rotation_index == 1
+ assert delegated_identity_key_2.rotation_index == 2
+ assert delegated_identity_key_last.rotation_index == 2
+
+ assert delegated_identity_key_0.private_key != delegated_identity_key_1.private_key
+ assert delegated_identity_key_1.private_key != delegated_identity_key_2.private_key
+ assert delegated_identity_key_0.private_key != delegated_identity_key_2.private_key
+ assert (
+ delegated_identity_key_last.private_key == delegated_identity_key_2.private_key
+ )
+
+ with pytest.raises(
+ TrezorFailure,
+ match=r"DataError: Requested rotation index \(3\) is higher than the current rotation index \(2\)",
+ ):
+ get_delegated_identity_key(client, rotation_index=3)
+
+
+def test_delegated_identity_key_rotation(client: Client):
+ delegated_identity_key_0 = get_delegated_identity_key(client)
+ assert delegated_identity_key_0.rotation_index is None
+
+ delegated_identity_key_1 = evolu.get_delegated_identity_key(
+ client.get_session(), rotate=True
+ )
+ assert delegated_identity_key_1.rotation_index == 1
+ assert delegated_identity_key_0.private_key != delegated_identity_key_1.private_key
+
+ delegated_identity_key_2 = evolu.get_delegated_identity_key(
+ client.get_session(), rotate=True
+ )
+ assert delegated_identity_key_2.rotation_index == 2
+ assert delegated_identity_key_1.private_key != delegated_identity_key_2.private_key
+ assert delegated_identity_key_0.private_key != delegated_identity_key_2.private_key
+
+
+def test_delegated_identity_key_rotation_max_index(client: Client):
+ # set rotation index to the maximum allowed value
+ evolu.index_management(client.get_session(), rotation_index=(1 << 16) - 1)
+
+ with pytest.raises(
+ TrezorFailure,
+ match="DataError: Maximum rotation index reached",
+ ):
+ evolu.get_delegated_identity_key(client.get_session(), rotate=True)
+
+
+def test_rotate_affects_index_management(client: Client):
+ evolu.get_delegated_identity_key(client.get_session(), rotate=True)
+
+ with pytest.raises(
+ TrezorFailure,
+ match=r"FirmwareError: Rotation index already set.",
+ ):
+ evolu.index_management(client.get_session(), rotation_index=50)
+
+ response = evolu.index_management(client.get_session())
+ assert response.rotation_index == 1
+
+
+def test_index_management_cannot_overwrite_existing_index(client: Client):
+ response = evolu.index_management(client.get_session(), rotation_index=10)
+ assert response.rotation_index == 10
+
+ with pytest.raises(
+ TrezorFailure,
+ match=r"FirmwareError: Rotation index already set.",
+ ):
+ evolu.index_management(client.get_session(), rotation_index=5)
+
+ with pytest.raises(
+ TrezorFailure,
+ match=r"FirmwareError: Rotation index already set.",
+ ):
+ evolu.index_management(client.get_session(), rotation_index=15)
+
+ key = get_delegated_identity_key(client)
+ assert key.rotation_index == 10
+
+
+def test_rotation_index_wiped_on_device_wipe(client: Client):
+ evolu.index_management(client.get_session(), rotation_index=0)
+ key_before_wipe_0 = get_delegated_identity_key(client)
+ assert key_before_wipe_0.rotation_index == 0
+ evolu.get_delegated_identity_key(client.get_session(), rotate=True)
+
+ key_before_wipe_1 = get_delegated_identity_key(client)
+ assert key_before_wipe_1.rotation_index == 1
+
+ session = client.get_session()
+ device.wipe(session)
+ session = client.get_seedless_session()
+ debuglink.load_device(
+ session,
+ mnemonic=" ".join(["all"] * 12),
+ pin=None,
+ passphrase_protection=False,
+ label="test",
+ )
+
+ key_after_wipe = get_delegated_identity_key(client)
+ assert key_after_wipe.rotation_index is None
+ assert key_before_wipe_1.private_key != key_after_wipe.private_key
+ assert key_before_wipe_0.private_key == key_after_wipe.private_key
+
+
+def test_index_management_getter(client: Client):
+ response = evolu.index_management(client.get_session(), rotation_index=None)
+ assert response.rotation_index is None
+
+ evolu.index_management(client.get_session(), rotation_index=5)
+
+ response = evolu.index_management(client.get_session(), rotation_index=None)
+ assert response.rotation_index == 5
+
+
+def test_explicit_index_zero_on_uninitialized_device(client: Client):
+ # Ensure device is uninitialized
+ response = evolu.index_management(client.get_session())
+ assert response.rotation_index is None
+
+ # Even though state is None, asking for explicit 0 should work
+ # because the firmware logic treats (None -> 0)
+ key_explicit = get_delegated_identity_key(client, rotation_index=0)
+
+ # The default fetch uses 0 for derivation but returns rotation_index=None in metadata
+ key_default = get_delegated_identity_key(client)
+
+ # Keys should be identical (both derived from index 0)
+ assert key_explicit.private_key == key_default.private_key
+
+ # But metadata differs: explicit request gets explicit index back
+ assert key_explicit.rotation_index == 0
+ assert key_default.rotation_index is None
diff --git a/tests/device_tests/evolu/test_get_delegated_identity_key.py b/tests/device_tests/evolu/test_get_delegated_identity_key.py
index 1e79ee0f..67ef87b4 100644
--- a/tests/device_tests/evolu/test_get_delegated_identity_key.py
+++ b/tests/device_tests/evolu/test_get_delegated_identity_key.py
@@ -14,10 +14,10 @@ pytestmark = [pytest.mark.models("core")]
def test_evolu_get_delegated_identity_is_constant(client: Client):
- private_key = get_delegated_identity_key(client)
+ private_key = get_delegated_identity_key(client).private_key
assert len(private_key) == 32
- private_key_2 = get_delegated_identity_key(client)
+ private_key_2 = get_delegated_identity_key(client).private_key
assert private_key_2 == private_key
@@ -26,7 +26,7 @@ def test_evolu_get_delegated_identity_test_vector(client: Client):
if not client.is_emulator:
pytest.skip("Only for emulator")
- private_key = get_delegated_identity_key(client)
+ private_key = get_delegated_identity_key(client).private_key
# hardcoded expected value for the emulator with zeroed master key
assert private_key == bytes.fromhex(
"10e39ed3a40dd63a47a14608d4bccd4501170cf9f2188223208084d39c37b369"
diff --git a/tests/device_tests/evolu/test_get_delegated_identity_key_thp.py b/tests/device_tests/evolu/test_get_delegated_identity_key_thp.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/tests/device_tests/evolu/test_get_node.py b/tests/device_tests/evolu/test_get_node.py
index 3b23f65d..98f17bed 100644
--- a/tests/device_tests/evolu/test_get_node.py
+++ b/tests/device_tests/evolu/test_get_node.py
@@ -17,7 +17,7 @@ pytestmark = [
def test_evolu_get_node(client: Client):
proof = get_proof(client, b"EvoluGetNode", [])
- node = evolu.get_node(client.get_session(), proof=proof)
+ node = evolu.get_node(client.get_session(), proof=proof, node_rotation_index=0)
# expected node for the SLIP-14 seed
check_value = bytes.fromhex(
@@ -29,11 +29,14 @@ def test_evolu_get_node(client: Client):
@pytest.mark.setup_client(
# a different seed
mnemonic="valve multiply shuffle venue then cruel genre venture fruit hammer sponsor luxury",
- passphrase=False,
+ passphrase=True,
)
-def test_evolu_get_node_different_seed(client: Client):
+@pytest.mark.parametrize("passphrase", ["", "TREZOR"])
+def test_evolu_get_node_different_seed(client: Client, passphrase: str):
proof = get_proof(client, b"EvoluGetNode", [])
- node = evolu.get_node(client.get_session(), proof=proof)
+ node = evolu.get_node(
+ client.get_session(passphrase=passphrase), proof=proof, node_rotation_index=0
+ )
# expected node for the SLIP-14 seed
check_value = bytes.fromhex(
@@ -51,7 +54,7 @@ def test_evolu_get_node_invalid_proof(client: Client):
TrezorFailure,
match="Invalid proof",
):
- evolu.get_node(client.get_session(), proof=invalid_proof)
+ evolu.get_node(client.get_session(), proof=invalid_proof, node_rotation_index=0)
def test_evolu_get_node_no_proof(client: Client):
@@ -59,7 +62,7 @@ def test_evolu_get_node_no_proof(client: Client):
TrezorFailure,
match="Invalid proof",
):
- evolu.get_node(client.get_session(), proof=b"")
+ evolu.get_node(client.get_session(), proof=b"", node_rotation_index=0)
def test_evolu_get_node_none_proof(client: Client):
@@ -67,4 +70,51 @@ def test_evolu_get_node_none_proof(client: Client):
TrezorFailure,
match="DataError: Failed to decode message: Missing required field. proof_of_delegated_identity",
):
- evolu.get_node(client.get_session(), proof=None) # type: ignore
+ evolu.get_node(client.get_session(), proof=None, node_rotation_index=0) # type: ignore
+
+
+def test_evolu_get_node_index_change(client: Client):
+ proof = bytes.fromhex(
+ "1fb521e8a4e4580377d530a9d6eb0a394ec8340fa42094d9f2e822bb944ce6a2074b81241b3b65dfa15d66e052f2504aba3ad1644844d695b181b3cdc9666cb66b"
+ )
+ node_index_0 = evolu.get_node(
+ client.get_session(), proof=proof, node_rotation_index=0
+ )
+ node_index_1 = evolu.get_node(
+ client.get_session(), proof=proof, node_rotation_index=1
+ )
+
+ assert node_index_0 != node_index_1
+
+
+def test_evolu_get_node_index_1(client: Client):
+ proof = bytes.fromhex(
+ "1fb521e8a4e4580377d530a9d6eb0a394ec8340fa42094d9f2e822bb944ce6a2074b81241b3b65dfa15d66e052f2504aba3ad1644844d695b181b3cdc9666cb66b"
+ )
+ node = evolu.get_node(client.get_session(), proof=proof, node_rotation_index=1)
+
+ check_value = bytes.fromhex(
+ "8465c8de92d35053d4de324166f2fbf73281a64a9e63661a7f4617890743152ae4b3989931093f9f9dda0eb30f1949899f14dfb145a51ef0e611dc99a8a4c742"
+ )
+ assert node == check_value
+
+
+@pytest.mark.parametrize("rotation_index", [None, 0, 42])
+@pytest.mark.parametrize("node_rotation_index", [0, 1])
+def test_evolu_get_node_with_different_rotation_indices(
+ client: Client, rotation_index, node_rotation_index
+):
+ evolu.index_management(client.get_session(), rotation_index=rotation_index)
+ proof = get_proof(
+ client,
+ b"EvoluGetNode",
+ [],
+ rotation_index=rotation_index,
+ )
+ node = evolu.get_node(
+ client.get_session(), proof=proof, node_rotation_index=node_rotation_index
+ )
+
+ # the proof should be valid regardless of the rotation indices used in the proof generation and in the get_node call, so we just check that we get some value back
+ assert isinstance(node, bytes)
+ assert len(node) == 64
diff --git a/tests/device_tests/evolu/test_sign_registration.py b/tests/device_tests/evolu/test_sign_registration.py
index 35b076b6..d3529065 100644
--- a/tests/device_tests/evolu/test_sign_registration.py
+++ b/tests/device_tests/evolu/test_sign_registration.py
@@ -38,7 +38,7 @@ def test_evolu_sign_request_t2t1(client: Client):
with pytest.raises(
TrezorFailure,
- match="Optiga is not available",
+ match="UnexpectedMessage: Unexpected message",
):
evolu.sign_registration_request(
client.get_session(),
@@ -52,7 +52,7 @@ def test_evolu_sign_request_t2t1(client: Client):
def test_evolu_sign_request(client: Client):
if optiga_unavailable(client):
pytest.xfail("Optiga is not available on this device.")
- delegated_identity_key = get_delegated_identity_key(client)
+ delegated_identity_key = get_delegated_identity_key(client).private_key
challenge = bytes.fromhex("1234")
size = 10
proposed_value = get_proof(
@@ -190,7 +190,7 @@ def test_evolu_sign_request_size_too_large(client: Client):
def test_evolu_sign_request_data_higher_bound(client: Client):
if optiga_unavailable(client):
pytest.xfail("Optiga is not available on this device.")
- delegated_identity_key = get_delegated_identity_key(client)
+ delegated_identity_key = get_delegated_identity_key(client).private_key
challenge = b"\x12" * 255
size = 0xFFFFFFFF
proof = get_proof(
@@ -210,3 +210,35 @@ def test_evolu_sign_request_data_higher_bound(client: Client):
check_signature_optiga(
response.signature, response.certificate_chain, client.model, data
)
+
+
+@pytest.mark.models("safe")
+@pytest.mark.parametrize("rotation_index", [None, 0, 1, 2, 42])
+def test_evolu_sign_request_with_different_rotation_indices(
+ client: Client, rotation_index
+):
+ if optiga_unavailable(client):
+ pytest.xfail("Optiga is not available on this device.")
+
+ evolu.index_management(client.get_session(), rotation_index=rotation_index)
+ delegated_identity_key = get_delegated_identity_key(client).private_key
+ challenge = bytes.fromhex("1234")
+ size = 10
+ proof = get_proof(
+ client,
+ b"EvoluSignRegistrationRequest",
+ [challenge, size.to_bytes(4, "big")],
+ rotation_index=rotation_index,
+ )
+
+ response = evolu.sign_registration_request(
+ client.get_session(),
+ challenge=challenge,
+ size=size,
+ proof=proof,
+ )
+
+ data = signing_buffer(delegated_identity_key, challenge, size)
+ check_signature_optiga(
+ response.signature, response.certificate_chain, client.model, data
+ )
diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json
index 2258eb06..9d26e6be 100644
--- a/tests/ui_tests/fixtures.json
+++ b/tests/ui_tests/fixtures.json
@@ -2278,13 +2278,31 @@
"T2T1_cs_ethereum-test_signtx.py::test_signtx_staking_eip1559[stake_main]": "e66c9d3a69d510dcabdd945b39025a1650fbc0fa9e2dc8a07084df09df30fd0a",
"T2T1_cs_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_hoodi]": "9117a7b537e2965276d6221462ad81ae669b92898f87eb3084b9450d3ec1444d",
"T2T1_cs_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_main]": "e1d94fab6c019487bb7640468c521e3fce77e0253504dac63fc9ae63bc6c623b",
+"T2T1_cs_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation": "d8ff84573b372f47813b68ca77d3c256702b51e31151fb521e5e67e294119cb7",
+"T2T1_cs_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_index_increment": "d5478068f580ef849e84f040d1082750b1cdc274ac34dc464c8119b21561f355",
+"T2T1_cs_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_max_index": "32d380b2c0942f8a2ab6a32e0e4c8a2ad2ab6750ee39c6fa4d4f0bacf59a4b7c",
+"T2T1_cs_evolu-test_delegated_identity_key_rotation.py::test_explicit_index_zero_on_uninitialized_device": "f2bde6f568fb9931f21513c3b1de7e7060939d93f289bb7c30d95b0ea5cacbdf",
+"T2T1_cs_evolu-test_delegated_identity_key_rotation.py::test_first_rotation_index_is_None": "f2bde6f568fb9931f21513c3b1de7e7060939d93f289bb7c30d95b0ea5cacbdf",
+"T2T1_cs_evolu-test_delegated_identity_key_rotation.py::test_index_management_cannot_overwrite_existing_index": "8e06e97a7a303e659ce3ddca98cb698d8d0595d381156552ff45738edf18b5fc",
+"T2T1_cs_evolu-test_delegated_identity_key_rotation.py::test_index_management_getter": "32d380b2c0942f8a2ab6a32e0e4c8a2ad2ab6750ee39c6fa4d4f0bacf59a4b7c",
+"T2T1_cs_evolu-test_delegated_identity_key_rotation.py::test_rotate_affects_index_management": "12e76a976afaa18f886142cf9072d45504e2d182311334d2bc352cc3b35f7b56",
+"T2T1_cs_evolu-test_delegated_identity_key_rotation.py::test_rotation_index_wiped_on_device_wipe": "716113d25a745014cab9ae70bad4ff1c2dfde9f6cb52cdc2ff34751aeef6def2",
"T2T1_cs_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_is_constant": "f2bde6f568fb9931f21513c3b1de7e7060939d93f289bb7c30d95b0ea5cacbdf",
"T2T1_cs_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_test_vector": "8e06e97a7a303e659ce3ddca98cb698d8d0595d381156552ff45738edf18b5fc",
"T2T1_cs_evolu-test_get_node.py::test_evolu_get_node": "8e06e97a7a303e659ce3ddca98cb698d8d0595d381156552ff45738edf18b5fc",
-"T2T1_cs_evolu-test_get_node.py::test_evolu_get_node_different_seed": "8e06e97a7a303e659ce3ddca98cb698d8d0595d381156552ff45738edf18b5fc",
+"T2T1_cs_evolu-test_get_node.py::test_evolu_get_node_different_seed[TREZOR]": "918eedb8ea3fa56c6413412fa71ab4546f2c87f4c6df84bdb946845ef161b55f",
+"T2T1_cs_evolu-test_get_node.py::test_evolu_get_node_different_seed[]": "8e06e97a7a303e659ce3ddca98cb698d8d0595d381156552ff45738edf18b5fc",
+"T2T1_cs_evolu-test_get_node.py::test_evolu_get_node_index_1": "32d380b2c0942f8a2ab6a32e0e4c8a2ad2ab6750ee39c6fa4d4f0bacf59a4b7c",
+"T2T1_cs_evolu-test_get_node.py::test_evolu_get_node_index_change": "32d380b2c0942f8a2ab6a32e0e4c8a2ad2ab6750ee39c6fa4d4f0bacf59a4b7c",
"T2T1_cs_evolu-test_get_node.py::test_evolu_get_node_invalid_proof": "8e06e97a7a303e659ce3ddca98cb698d8d0595d381156552ff45738edf18b5fc",
"T2T1_cs_evolu-test_get_node.py::test_evolu_get_node_no_proof": "32d380b2c0942f8a2ab6a32e0e4c8a2ad2ab6750ee39c6fa4d4f0bacf59a4b7c",
"T2T1_cs_evolu-test_get_node.py::test_evolu_get_node_none_proof": "32d380b2c0942f8a2ab6a32e0e4c8a2ad2ab6750ee39c6fa4d4f0bacf59a4b7c",
+"T2T1_cs_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-0]": "8e06e97a7a303e659ce3ddca98cb698d8d0595d381156552ff45738edf18b5fc",
+"T2T1_cs_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-42]": "8e06e97a7a303e659ce3ddca98cb698d8d0595d381156552ff45738edf18b5fc",
+"T2T1_cs_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-None]": "8e06e97a7a303e659ce3ddca98cb698d8d0595d381156552ff45738edf18b5fc",
+"T2T1_cs_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-0]": "8e06e97a7a303e659ce3ddca98cb698d8d0595d381156552ff45738edf18b5fc",
+"T2T1_cs_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-42]": "8e06e97a7a303e659ce3ddca98cb698d8d0595d381156552ff45738edf18b5fc",
+"T2T1_cs_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-None]": "8e06e97a7a303e659ce3ddca98cb698d8d0595d381156552ff45738edf18b5fc",
"T2T1_cs_evolu-test_sign_registration.py::test_evolu_sign_request_t2t1": "8e06e97a7a303e659ce3ddca98cb698d8d0595d381156552ff45738edf18b5fc",
"T2T1_cs_misc-test_msg_cipherkeyvalue.py::test_decrypt": "5f31238f8766628e1948d79f7e9ac209c8c259a04f0c2efe27880da3ac167ed2",
"T2T1_cs_misc-test_msg_cipherkeyvalue.py::test_decrypt_badlen": "32d380b2c0942f8a2ab6a32e0e4c8a2ad2ab6750ee39c6fa4d4f0bacf59a4b7c",
@@ -3924,13 +3942,31 @@
"T2T1_de_ethereum-test_signtx.py::test_signtx_staking_eip1559[stake_main]": "2f7638e72122674b27efbb795c0aa3687b267ffaf765b98d9d01b623265b111d",
"T2T1_de_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_hoodi]": "e42a8b3eee5bad27af12e12af255e63b559542e3a5064261303e7f8b5545e05d",
"T2T1_de_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_main]": "a057de4ff90bb06c19c620b2d5eee5bcce2a8f56440cc2790fedefde2412b59d",
+"T2T1_de_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation": "ce969ab0a0dc961d8718ff65cb75fd12eaa87f596dc735263a3fa594c7ec503b",
+"T2T1_de_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_index_increment": "df074a2bc30404fb473016e72e3277ac61dd6fd40f067649bfcc6948db4c616c",
+"T2T1_de_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_max_index": "a3edf3ced8fa1fa6b9f67f869a28bc880ce5e214b0adfaf839cd867875845912",
+"T2T1_de_evolu-test_delegated_identity_key_rotation.py::test_explicit_index_zero_on_uninitialized_device": "5691b9992491cf75f067b3e62efa75db40cba7bc19abe78cf49c46b4e899d2ee",
+"T2T1_de_evolu-test_delegated_identity_key_rotation.py::test_first_rotation_index_is_None": "5691b9992491cf75f067b3e62efa75db40cba7bc19abe78cf49c46b4e899d2ee",
+"T2T1_de_evolu-test_delegated_identity_key_rotation.py::test_index_management_cannot_overwrite_existing_index": "890e2bd8bc8ab9b8d3f318ee707775e808dd99f719760ce73639861ab8c5127f",
+"T2T1_de_evolu-test_delegated_identity_key_rotation.py::test_index_management_getter": "a3edf3ced8fa1fa6b9f67f869a28bc880ce5e214b0adfaf839cd867875845912",
+"T2T1_de_evolu-test_delegated_identity_key_rotation.py::test_rotate_affects_index_management": "27bb27412a9571e1edb192f2ad3788e0495fc8dacc12cfc11019e944cf238fc2",
+"T2T1_de_evolu-test_delegated_identity_key_rotation.py::test_rotation_index_wiped_on_device_wipe": "64f80b54ebc84c20f8333ffa9c5790815550526e3aef53b6d3e0d340d3fad4c0",
"T2T1_de_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_is_constant": "5691b9992491cf75f067b3e62efa75db40cba7bc19abe78cf49c46b4e899d2ee",
"T2T1_de_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_test_vector": "890e2bd8bc8ab9b8d3f318ee707775e808dd99f719760ce73639861ab8c5127f",
"T2T1_de_evolu-test_get_node.py::test_evolu_get_node": "890e2bd8bc8ab9b8d3f318ee707775e808dd99f719760ce73639861ab8c5127f",
-"T2T1_de_evolu-test_get_node.py::test_evolu_get_node_different_seed": "890e2bd8bc8ab9b8d3f318ee707775e808dd99f719760ce73639861ab8c5127f",
+"T2T1_de_evolu-test_get_node.py::test_evolu_get_node_different_seed[TREZOR]": "62b9b963ed43b8e1cbec464e5d10c501bc6ab66aa52c55f2f272e98ef4ed356a",
+"T2T1_de_evolu-test_get_node.py::test_evolu_get_node_different_seed[]": "890e2bd8bc8ab9b8d3f318ee707775e808dd99f719760ce73639861ab8c5127f",
+"T2T1_de_evolu-test_get_node.py::test_evolu_get_node_index_1": "a3edf3ced8fa1fa6b9f67f869a28bc880ce5e214b0adfaf839cd867875845912",
+"T2T1_de_evolu-test_get_node.py::test_evolu_get_node_index_change": "a3edf3ced8fa1fa6b9f67f869a28bc880ce5e214b0adfaf839cd867875845912",
"T2T1_de_evolu-test_get_node.py::test_evolu_get_node_invalid_proof": "890e2bd8bc8ab9b8d3f318ee707775e808dd99f719760ce73639861ab8c5127f",
"T2T1_de_evolu-test_get_node.py::test_evolu_get_node_no_proof": "a3edf3ced8fa1fa6b9f67f869a28bc880ce5e214b0adfaf839cd867875845912",
"T2T1_de_evolu-test_get_node.py::test_evolu_get_node_none_proof": "a3edf3ced8fa1fa6b9f67f869a28bc880ce5e214b0adfaf839cd867875845912",
+"T2T1_de_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-0]": "890e2bd8bc8ab9b8d3f318ee707775e808dd99f719760ce73639861ab8c5127f",
+"T2T1_de_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-42]": "890e2bd8bc8ab9b8d3f318ee707775e808dd99f719760ce73639861ab8c5127f",
+"T2T1_de_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-None]": "890e2bd8bc8ab9b8d3f318ee707775e808dd99f719760ce73639861ab8c5127f",
+"T2T1_de_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-0]": "890e2bd8bc8ab9b8d3f318ee707775e808dd99f719760ce73639861ab8c5127f",
+"T2T1_de_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-42]": "890e2bd8bc8ab9b8d3f318ee707775e808dd99f719760ce73639861ab8c5127f",
+"T2T1_de_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-None]": "890e2bd8bc8ab9b8d3f318ee707775e808dd99f719760ce73639861ab8c5127f",
"T2T1_de_evolu-test_sign_registration.py::test_evolu_sign_request_t2t1": "890e2bd8bc8ab9b8d3f318ee707775e808dd99f719760ce73639861ab8c5127f",
"T2T1_de_misc-test_msg_cipherkeyvalue.py::test_decrypt": "f0aca8a0ba9af0c35042fa2c6fc1eeb34fde3f0cd6a2dc846c7ea2c22b1b0d5c",
"T2T1_de_misc-test_msg_cipherkeyvalue.py::test_decrypt_badlen": "a3edf3ced8fa1fa6b9f67f869a28bc880ce5e214b0adfaf839cd867875845912",
@@ -5570,13 +5606,31 @@
"T2T1_en_ethereum-test_signtx.py::test_signtx_staking_eip1559[stake_main]": "b9bb91d5beb047e5241d9203899f8a5bef07cfdebe98bef11109ef83180378a3",
"T2T1_en_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_hoodi]": "784bfad1d6b99578c97b941530468f22b88157de3e95b60c1744acdb481f06d0",
"T2T1_en_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_main]": "9e0e885b76010709d49853eac137a4819172aa48a720220ab869ec121d5c3529",
+"T2T1_en_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation": "9e866dc07529b53e6e9ca1e252a6a7ddfd03b27cbddc19025745dd09c6060ad6",
+"T2T1_en_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_index_increment": "d8cfff286862232edd67e5e447fc0bc93df446fe12f975a726fee8f1bb76b87e",
+"T2T1_en_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_max_index": "8b1ccc0dbd6e6e3d02a896650ab90dd332ba4edbbcc4095e0fbb6a96e5256f75",
+"T2T1_en_evolu-test_delegated_identity_key_rotation.py::test_explicit_index_zero_on_uninitialized_device": "a5cfc8d4c9fba285b6489d80e71e9a3dc5d344dfe1651ba035da3cda3810338b",
+"T2T1_en_evolu-test_delegated_identity_key_rotation.py::test_first_rotation_index_is_None": "a5cfc8d4c9fba285b6489d80e71e9a3dc5d344dfe1651ba035da3cda3810338b",
+"T2T1_en_evolu-test_delegated_identity_key_rotation.py::test_index_management_cannot_overwrite_existing_index": "4f2ddb00cec6b62a046f1a2333dc4ff23f2528a53b84fe1e533f33e43d814487",
+"T2T1_en_evolu-test_delegated_identity_key_rotation.py::test_index_management_getter": "8b1ccc0dbd6e6e3d02a896650ab90dd332ba4edbbcc4095e0fbb6a96e5256f75",
+"T2T1_en_evolu-test_delegated_identity_key_rotation.py::test_rotate_affects_index_management": "30848648bfd834d23a2e4e3e320a7351a38e24683ad886604f739d394bc181ff",
+"T2T1_en_evolu-test_delegated_identity_key_rotation.py::test_rotation_index_wiped_on_device_wipe": "f0f7605e0df4409db87c07177bc7a9822182b7d1848b3a4f09cddf1eb94a91f5",
"T2T1_en_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_is_constant": "a5cfc8d4c9fba285b6489d80e71e9a3dc5d344dfe1651ba035da3cda3810338b",
"T2T1_en_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_test_vector": "4f2ddb00cec6b62a046f1a2333dc4ff23f2528a53b84fe1e533f33e43d814487",
"T2T1_en_evolu-test_get_node.py::test_evolu_get_node": "4f2ddb00cec6b62a046f1a2333dc4ff23f2528a53b84fe1e533f33e43d814487",
-"T2T1_en_evolu-test_get_node.py::test_evolu_get_node_different_seed": "4f2ddb00cec6b62a046f1a2333dc4ff23f2528a53b84fe1e533f33e43d814487",
+"T2T1_en_evolu-test_get_node.py::test_evolu_get_node_different_seed[TREZOR]": "3136d703b3fc226bd39b00706a1c6456d4275dd502a64d7d389d51b8ba75e87b",
+"T2T1_en_evolu-test_get_node.py::test_evolu_get_node_different_seed[]": "4f2ddb00cec6b62a046f1a2333dc4ff23f2528a53b84fe1e533f33e43d814487",
+"T2T1_en_evolu-test_get_node.py::test_evolu_get_node_index_1": "8b1ccc0dbd6e6e3d02a896650ab90dd332ba4edbbcc4095e0fbb6a96e5256f75",
+"T2T1_en_evolu-test_get_node.py::test_evolu_get_node_index_change": "8b1ccc0dbd6e6e3d02a896650ab90dd332ba4edbbcc4095e0fbb6a96e5256f75",
"T2T1_en_evolu-test_get_node.py::test_evolu_get_node_invalid_proof": "4f2ddb00cec6b62a046f1a2333dc4ff23f2528a53b84fe1e533f33e43d814487",
"T2T1_en_evolu-test_get_node.py::test_evolu_get_node_no_proof": "8b1ccc0dbd6e6e3d02a896650ab90dd332ba4edbbcc4095e0fbb6a96e5256f75",
"T2T1_en_evolu-test_get_node.py::test_evolu_get_node_none_proof": "8b1ccc0dbd6e6e3d02a896650ab90dd332ba4edbbcc4095e0fbb6a96e5256f75",
+"T2T1_en_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-0]": "4f2ddb00cec6b62a046f1a2333dc4ff23f2528a53b84fe1e533f33e43d814487",
+"T2T1_en_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-42]": "4f2ddb00cec6b62a046f1a2333dc4ff23f2528a53b84fe1e533f33e43d814487",
+"T2T1_en_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-None]": "4f2ddb00cec6b62a046f1a2333dc4ff23f2528a53b84fe1e533f33e43d814487",
+"T2T1_en_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-0]": "4f2ddb00cec6b62a046f1a2333dc4ff23f2528a53b84fe1e533f33e43d814487",
+"T2T1_en_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-42]": "4f2ddb00cec6b62a046f1a2333dc4ff23f2528a53b84fe1e533f33e43d814487",
+"T2T1_en_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-None]": "4f2ddb00cec6b62a046f1a2333dc4ff23f2528a53b84fe1e533f33e43d814487",
"T2T1_en_evolu-test_sign_registration.py::test_evolu_sign_request_t2t1": "4f2ddb00cec6b62a046f1a2333dc4ff23f2528a53b84fe1e533f33e43d814487",
"T2T1_en_misc-test_msg_cipherkeyvalue.py::test_decrypt": "34e053b4d18d9debecdf9a83d517c0eec3468a599dec8b816cdee8ba64fa9051",
"T2T1_en_misc-test_msg_cipherkeyvalue.py::test_decrypt_badlen": "8b1ccc0dbd6e6e3d02a896650ab90dd332ba4edbbcc4095e0fbb6a96e5256f75",
@@ -7234,13 +7288,31 @@
"T2T1_es_ethereum-test_signtx.py::test_signtx_staking_eip1559[stake_main]": "e890cea792a8eb43ade69488aa23a682e286ce80139be393220164d6b7a744ab",
"T2T1_es_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_hoodi]": "837da3bf5cd9c112c489aedb377374bdf9cb040a075c7e3962e698fad6e609b3",
"T2T1_es_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_main]": "4de136e647f9e0b2c7a2b1737b71cd21a89a6509ccdd1fdc3258b5ebf80e2d3e",
+"T2T1_es_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation": "b2ae9dd2180565062fc9745a14a8150faa17206413cb9705c393539c65a546f5",
+"T2T1_es_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_index_increment": "760bc5bc529519e9a43e37950cd100f3702dcf891c4b13c1b32e3a69afdda738",
+"T2T1_es_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_max_index": "1775658fa541fff7933453c1d346449c492079a39341e07135ac9e7662b3bbd3",
+"T2T1_es_evolu-test_delegated_identity_key_rotation.py::test_explicit_index_zero_on_uninitialized_device": "5fbc0f3cdf5ca6a64d1cc6ba9775e4df9eb868dd1d7d4bc7711d4f238b35780f",
+"T2T1_es_evolu-test_delegated_identity_key_rotation.py::test_first_rotation_index_is_None": "5fbc0f3cdf5ca6a64d1cc6ba9775e4df9eb868dd1d7d4bc7711d4f238b35780f",
+"T2T1_es_evolu-test_delegated_identity_key_rotation.py::test_index_management_cannot_overwrite_existing_index": "fe683b4d7a676e829f44ea50aaee1c6c07ef0a56baa08d78f5e1dfa1d7a7bd27",
+"T2T1_es_evolu-test_delegated_identity_key_rotation.py::test_index_management_getter": "1775658fa541fff7933453c1d346449c492079a39341e07135ac9e7662b3bbd3",
+"T2T1_es_evolu-test_delegated_identity_key_rotation.py::test_rotate_affects_index_management": "0be695e13341d0ab70c2b685caa597e7babf7bbea9a3e50dc92dd059c60fb91c",
+"T2T1_es_evolu-test_delegated_identity_key_rotation.py::test_rotation_index_wiped_on_device_wipe": "914598d7aea388d3909be9808343e4284798cfcfd770fff2491fa59b43537942",
"T2T1_es_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_is_constant": "5fbc0f3cdf5ca6a64d1cc6ba9775e4df9eb868dd1d7d4bc7711d4f238b35780f",
"T2T1_es_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_test_vector": "fe683b4d7a676e829f44ea50aaee1c6c07ef0a56baa08d78f5e1dfa1d7a7bd27",
"T2T1_es_evolu-test_get_node.py::test_evolu_get_node": "fe683b4d7a676e829f44ea50aaee1c6c07ef0a56baa08d78f5e1dfa1d7a7bd27",
-"T2T1_es_evolu-test_get_node.py::test_evolu_get_node_different_seed": "fe683b4d7a676e829f44ea50aaee1c6c07ef0a56baa08d78f5e1dfa1d7a7bd27",
+"T2T1_es_evolu-test_get_node.py::test_evolu_get_node_different_seed[TREZOR]": "8a30c581b55bec7d8bd421a4c203376ac6f6efd85b2ca70f9901a9a113c93295",
+"T2T1_es_evolu-test_get_node.py::test_evolu_get_node_different_seed[]": "fe683b4d7a676e829f44ea50aaee1c6c07ef0a56baa08d78f5e1dfa1d7a7bd27",
+"T2T1_es_evolu-test_get_node.py::test_evolu_get_node_index_1": "1775658fa541fff7933453c1d346449c492079a39341e07135ac9e7662b3bbd3",
+"T2T1_es_evolu-test_get_node.py::test_evolu_get_node_index_change": "1775658fa541fff7933453c1d346449c492079a39341e07135ac9e7662b3bbd3",
"T2T1_es_evolu-test_get_node.py::test_evolu_get_node_invalid_proof": "fe683b4d7a676e829f44ea50aaee1c6c07ef0a56baa08d78f5e1dfa1d7a7bd27",
"T2T1_es_evolu-test_get_node.py::test_evolu_get_node_no_proof": "1775658fa541fff7933453c1d346449c492079a39341e07135ac9e7662b3bbd3",
"T2T1_es_evolu-test_get_node.py::test_evolu_get_node_none_proof": "1775658fa541fff7933453c1d346449c492079a39341e07135ac9e7662b3bbd3",
+"T2T1_es_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-0]": "fe683b4d7a676e829f44ea50aaee1c6c07ef0a56baa08d78f5e1dfa1d7a7bd27",
+"T2T1_es_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-42]": "fe683b4d7a676e829f44ea50aaee1c6c07ef0a56baa08d78f5e1dfa1d7a7bd27",
+"T2T1_es_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-None]": "fe683b4d7a676e829f44ea50aaee1c6c07ef0a56baa08d78f5e1dfa1d7a7bd27",
+"T2T1_es_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-0]": "fe683b4d7a676e829f44ea50aaee1c6c07ef0a56baa08d78f5e1dfa1d7a7bd27",
+"T2T1_es_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-42]": "fe683b4d7a676e829f44ea50aaee1c6c07ef0a56baa08d78f5e1dfa1d7a7bd27",
+"T2T1_es_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-None]": "fe683b4d7a676e829f44ea50aaee1c6c07ef0a56baa08d78f5e1dfa1d7a7bd27",
"T2T1_es_evolu-test_sign_registration.py::test_evolu_sign_request_t2t1": "fe683b4d7a676e829f44ea50aaee1c6c07ef0a56baa08d78f5e1dfa1d7a7bd27",
"T2T1_es_misc-test_msg_cipherkeyvalue.py::test_decrypt": "14a81a6f25734c2e0ac6cf90e9b975669d8e7719764bf8fdb2c89358a011f547",
"T2T1_es_misc-test_msg_cipherkeyvalue.py::test_decrypt_badlen": "1775658fa541fff7933453c1d346449c492079a39341e07135ac9e7662b3bbd3",
@@ -8880,13 +8952,31 @@
"T2T1_fr_ethereum-test_signtx.py::test_signtx_staking_eip1559[stake_main]": "b24ee8f6d7f246bd52f03f03f78ab185c078fd0a2a85c3bec3768c969ee32fe6",
"T2T1_fr_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_hoodi]": "b2663c692d763ef1b99f3494fe8706040c540f3662ca5768de98f9f3ae804086",
"T2T1_fr_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_main]": "0cb353d85c3053ddb635632d7cc85fa7a9c3e414a09f8bec35b51911a2daada5",
+"T2T1_fr_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation": "98413739fc6fd1687d31632b745f8439ef8911efc32c5ac24a6559724f490f12",
+"T2T1_fr_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_index_increment": "045dc025cc61b2d0803a727657fa3257f6673eedac3f7d14101445b5d89c51c6",
+"T2T1_fr_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_max_index": "94d3ba1cba15b836e6ebc48ab307aeea71275ef2d9849aaabc8e883df555ce3f",
+"T2T1_fr_evolu-test_delegated_identity_key_rotation.py::test_explicit_index_zero_on_uninitialized_device": "75e5a2fd9de37794a65a78a46a36b5c15f6782fcd409b30aee9a10bfd20cb73d",
+"T2T1_fr_evolu-test_delegated_identity_key_rotation.py::test_first_rotation_index_is_None": "75e5a2fd9de37794a65a78a46a36b5c15f6782fcd409b30aee9a10bfd20cb73d",
+"T2T1_fr_evolu-test_delegated_identity_key_rotation.py::test_index_management_cannot_overwrite_existing_index": "1d2f34883b1d8f50be7f86272b5f02a2a7e10efa03306ba9597df789b7e1d95c",
+"T2T1_fr_evolu-test_delegated_identity_key_rotation.py::test_index_management_getter": "94d3ba1cba15b836e6ebc48ab307aeea71275ef2d9849aaabc8e883df555ce3f",
+"T2T1_fr_evolu-test_delegated_identity_key_rotation.py::test_rotate_affects_index_management": "e59fec5d2b8f9160ad684eb51f7783a76c9a1e9cfba7a943ffea81bb935f18fb",
+"T2T1_fr_evolu-test_delegated_identity_key_rotation.py::test_rotation_index_wiped_on_device_wipe": "4f9c73ab99520075077dc5cfa8958c7761a8301fa4b2cf4d1862f3c24678baa7",
"T2T1_fr_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_is_constant": "75e5a2fd9de37794a65a78a46a36b5c15f6782fcd409b30aee9a10bfd20cb73d",
"T2T1_fr_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_test_vector": "1d2f34883b1d8f50be7f86272b5f02a2a7e10efa03306ba9597df789b7e1d95c",
"T2T1_fr_evolu-test_get_node.py::test_evolu_get_node": "1d2f34883b1d8f50be7f86272b5f02a2a7e10efa03306ba9597df789b7e1d95c",
-"T2T1_fr_evolu-test_get_node.py::test_evolu_get_node_different_seed": "1d2f34883b1d8f50be7f86272b5f02a2a7e10efa03306ba9597df789b7e1d95c",
+"T2T1_fr_evolu-test_get_node.py::test_evolu_get_node_different_seed[TREZOR]": "c047baa2dd0eba6990d25fcc1f6abb4bdae37edb0e4e64c654bdb7360c7cabad",
+"T2T1_fr_evolu-test_get_node.py::test_evolu_get_node_different_seed[]": "1d2f34883b1d8f50be7f86272b5f02a2a7e10efa03306ba9597df789b7e1d95c",
+"T2T1_fr_evolu-test_get_node.py::test_evolu_get_node_index_1": "94d3ba1cba15b836e6ebc48ab307aeea71275ef2d9849aaabc8e883df555ce3f",
+"T2T1_fr_evolu-test_get_node.py::test_evolu_get_node_index_change": "94d3ba1cba15b836e6ebc48ab307aeea71275ef2d9849aaabc8e883df555ce3f",
"T2T1_fr_evolu-test_get_node.py::test_evolu_get_node_invalid_proof": "1d2f34883b1d8f50be7f86272b5f02a2a7e10efa03306ba9597df789b7e1d95c",
"T2T1_fr_evolu-test_get_node.py::test_evolu_get_node_no_proof": "94d3ba1cba15b836e6ebc48ab307aeea71275ef2d9849aaabc8e883df555ce3f",
"T2T1_fr_evolu-test_get_node.py::test_evolu_get_node_none_proof": "94d3ba1cba15b836e6ebc48ab307aeea71275ef2d9849aaabc8e883df555ce3f",
+"T2T1_fr_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-0]": "1d2f34883b1d8f50be7f86272b5f02a2a7e10efa03306ba9597df789b7e1d95c",
+"T2T1_fr_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-42]": "1d2f34883b1d8f50be7f86272b5f02a2a7e10efa03306ba9597df789b7e1d95c",
+"T2T1_fr_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-None]": "1d2f34883b1d8f50be7f86272b5f02a2a7e10efa03306ba9597df789b7e1d95c",
+"T2T1_fr_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-0]": "1d2f34883b1d8f50be7f86272b5f02a2a7e10efa03306ba9597df789b7e1d95c",
+"T2T1_fr_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-42]": "1d2f34883b1d8f50be7f86272b5f02a2a7e10efa03306ba9597df789b7e1d95c",
+"T2T1_fr_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-None]": "1d2f34883b1d8f50be7f86272b5f02a2a7e10efa03306ba9597df789b7e1d95c",
"T2T1_fr_evolu-test_sign_registration.py::test_evolu_sign_request_t2t1": "1d2f34883b1d8f50be7f86272b5f02a2a7e10efa03306ba9597df789b7e1d95c",
"T2T1_fr_misc-test_msg_cipherkeyvalue.py::test_decrypt": "1db34d5c37a59b43ff39cb637441c89e6ed71011cb2445b82872326d81a2721a",
"T2T1_fr_misc-test_msg_cipherkeyvalue.py::test_decrypt_badlen": "94d3ba1cba15b836e6ebc48ab307aeea71275ef2d9849aaabc8e883df555ce3f",
@@ -10526,13 +10616,31 @@
"T2T1_pt_ethereum-test_signtx.py::test_signtx_staking_eip1559[stake_main]": "75c84f15fe12d6a68c37273c3241af09bb939e57621fb149ed245f73f64ff390",
"T2T1_pt_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_hoodi]": "808aa4cbb9b4becc9a8af790a188cfd9d9cca4a6704ec112aac136b733de26bc",
"T2T1_pt_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_main]": "280c25159c33a068f0ad6268bce6d796d2a2298b9d94566e1f4f72ac51544a72",
+"T2T1_pt_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation": "e2210c5192017c7f0a8d10979bee30fefb2f2a809f9945541e051cb9c6e3ed17",
+"T2T1_pt_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_index_increment": "14be862fb1516e193e93433959e5f194cd6d936014c6b1b61af0b0068289bbd1",
+"T2T1_pt_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_max_index": "e9e80e1bfd347b598699a7a84deb8932eff90fc5fb8b56771453e06fe3c4c216",
+"T2T1_pt_evolu-test_delegated_identity_key_rotation.py::test_explicit_index_zero_on_uninitialized_device": "5405f2c91a32c7a781466b989e3596a4501aeaa9d7aa1ee774ce1e9b8bbbd7f2",
+"T2T1_pt_evolu-test_delegated_identity_key_rotation.py::test_first_rotation_index_is_None": "5405f2c91a32c7a781466b989e3596a4501aeaa9d7aa1ee774ce1e9b8bbbd7f2",
+"T2T1_pt_evolu-test_delegated_identity_key_rotation.py::test_index_management_cannot_overwrite_existing_index": "9f8e735311d479762358b49a3fcba273722954ea3957787d0af0758fcb6e6919",
+"T2T1_pt_evolu-test_delegated_identity_key_rotation.py::test_index_management_getter": "e9e80e1bfd347b598699a7a84deb8932eff90fc5fb8b56771453e06fe3c4c216",
+"T2T1_pt_evolu-test_delegated_identity_key_rotation.py::test_rotate_affects_index_management": "26b65ef7532303a48a4d702289963fb6cd1272b2674b28442402d506b81565de",
+"T2T1_pt_evolu-test_delegated_identity_key_rotation.py::test_rotation_index_wiped_on_device_wipe": "de3b31af1214952078c12fb56be3195437dd8e0e7849f88d544fc81d88fa0ae3",
"T2T1_pt_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_is_constant": "5405f2c91a32c7a781466b989e3596a4501aeaa9d7aa1ee774ce1e9b8bbbd7f2",
"T2T1_pt_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_test_vector": "9f8e735311d479762358b49a3fcba273722954ea3957787d0af0758fcb6e6919",
"T2T1_pt_evolu-test_get_node.py::test_evolu_get_node": "9f8e735311d479762358b49a3fcba273722954ea3957787d0af0758fcb6e6919",
-"T2T1_pt_evolu-test_get_node.py::test_evolu_get_node_different_seed": "9f8e735311d479762358b49a3fcba273722954ea3957787d0af0758fcb6e6919",
+"T2T1_pt_evolu-test_get_node.py::test_evolu_get_node_different_seed[TREZOR]": "619bbe73877d8c35dd4f741f02e36908609d4d966596252606d76e437a43bb1d",
+"T2T1_pt_evolu-test_get_node.py::test_evolu_get_node_different_seed[]": "9f8e735311d479762358b49a3fcba273722954ea3957787d0af0758fcb6e6919",
+"T2T1_pt_evolu-test_get_node.py::test_evolu_get_node_index_1": "e9e80e1bfd347b598699a7a84deb8932eff90fc5fb8b56771453e06fe3c4c216",
+"T2T1_pt_evolu-test_get_node.py::test_evolu_get_node_index_change": "e9e80e1bfd347b598699a7a84deb8932eff90fc5fb8b56771453e06fe3c4c216",
"T2T1_pt_evolu-test_get_node.py::test_evolu_get_node_invalid_proof": "9f8e735311d479762358b49a3fcba273722954ea3957787d0af0758fcb6e6919",
"T2T1_pt_evolu-test_get_node.py::test_evolu_get_node_no_proof": "e9e80e1bfd347b598699a7a84deb8932eff90fc5fb8b56771453e06fe3c4c216",
"T2T1_pt_evolu-test_get_node.py::test_evolu_get_node_none_proof": "e9e80e1bfd347b598699a7a84deb8932eff90fc5fb8b56771453e06fe3c4c216",
+"T2T1_pt_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-0]": "9f8e735311d479762358b49a3fcba273722954ea3957787d0af0758fcb6e6919",
+"T2T1_pt_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-42]": "9f8e735311d479762358b49a3fcba273722954ea3957787d0af0758fcb6e6919",
+"T2T1_pt_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-None]": "9f8e735311d479762358b49a3fcba273722954ea3957787d0af0758fcb6e6919",
+"T2T1_pt_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-0]": "9f8e735311d479762358b49a3fcba273722954ea3957787d0af0758fcb6e6919",
+"T2T1_pt_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-42]": "9f8e735311d479762358b49a3fcba273722954ea3957787d0af0758fcb6e6919",
+"T2T1_pt_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-None]": "9f8e735311d479762358b49a3fcba273722954ea3957787d0af0758fcb6e6919",
"T2T1_pt_evolu-test_sign_registration.py::test_evolu_sign_request_t2t1": "9f8e735311d479762358b49a3fcba273722954ea3957787d0af0758fcb6e6919",
"T2T1_pt_misc-test_msg_cipherkeyvalue.py::test_decrypt": "d03884ab0ff6c1839c7702c3a08decdd9656f76acbea17bac578540f0ce82ec5",
"T2T1_pt_misc-test_msg_cipherkeyvalue.py::test_decrypt_badlen": "e9e80e1bfd347b598699a7a84deb8932eff90fc5fb8b56771453e06fe3c4c216",
@@ -12423,13 +12531,31 @@
"T3B1_cs_ethereum-test_signtx.py::test_signtx_staking_eip1559[stake_main]": "eecdbe96d8649af840c34f7650f6dba35db3c095b76f0d85f78fc7f18d6affb7",
"T3B1_cs_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_hoodi]": "f128c70c803c584f963ad7370769d2e8a5b852e6de3e4f3f1e9a798666162041",
"T3B1_cs_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_main]": "3bb2921ad04452090f5ea5cf47b615f984860568580809ad5f143bbb74a65748",
+"T3B1_cs_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation": "c9cc1aca29c80a5cdc2710be8fbf0c16333ecfd2e2693c08f2952301fd54c4f6",
+"T3B1_cs_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_index_increment": "d9636fcf4565f8444a449eb8fb092acde3ddd7baa1d7122be4140abc520a9b5b",
+"T3B1_cs_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_max_index": "92840d4624bb07440bb1ab5cb4b57251c9950388accbc8334a9a7d609ededb01",
+"T3B1_cs_evolu-test_delegated_identity_key_rotation.py::test_explicit_index_zero_on_uninitialized_device": "78e068c30568e38df05db147e60378a939ea3d2d325f18aba0208c275333921b",
+"T3B1_cs_evolu-test_delegated_identity_key_rotation.py::test_first_rotation_index_is_None": "78e068c30568e38df05db147e60378a939ea3d2d325f18aba0208c275333921b",
+"T3B1_cs_evolu-test_delegated_identity_key_rotation.py::test_index_management_cannot_overwrite_existing_index": "1aaf307e406fdd1cd3232ab62db7bf1437907afa1863f99bae65e8b9b66f5b45",
+"T3B1_cs_evolu-test_delegated_identity_key_rotation.py::test_index_management_getter": "92840d4624bb07440bb1ab5cb4b57251c9950388accbc8334a9a7d609ededb01",
+"T3B1_cs_evolu-test_delegated_identity_key_rotation.py::test_rotate_affects_index_management": "a3f1537b31fc014a05758831dda7b278840864a39702205bbb797d544271aa52",
+"T3B1_cs_evolu-test_delegated_identity_key_rotation.py::test_rotation_index_wiped_on_device_wipe": "076832950abc2ebaa887c6f18738ec01c8a131b9cb355928feef8e43e5af832c",
"T3B1_cs_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_is_constant": "78e068c30568e38df05db147e60378a939ea3d2d325f18aba0208c275333921b",
"T3B1_cs_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_test_vector": "1aaf307e406fdd1cd3232ab62db7bf1437907afa1863f99bae65e8b9b66f5b45",
"T3B1_cs_evolu-test_get_node.py::test_evolu_get_node": "1aaf307e406fdd1cd3232ab62db7bf1437907afa1863f99bae65e8b9b66f5b45",
-"T3B1_cs_evolu-test_get_node.py::test_evolu_get_node_different_seed": "1aaf307e406fdd1cd3232ab62db7bf1437907afa1863f99bae65e8b9b66f5b45",
+"T3B1_cs_evolu-test_get_node.py::test_evolu_get_node_different_seed[TREZOR]": "e21f5ac22865ac1b0895f03893edff5e239dade16d151b763b4b750ff3234ccf",
+"T3B1_cs_evolu-test_get_node.py::test_evolu_get_node_different_seed[]": "1aaf307e406fdd1cd3232ab62db7bf1437907afa1863f99bae65e8b9b66f5b45",
+"T3B1_cs_evolu-test_get_node.py::test_evolu_get_node_index_1": "92840d4624bb07440bb1ab5cb4b57251c9950388accbc8334a9a7d609ededb01",
+"T3B1_cs_evolu-test_get_node.py::test_evolu_get_node_index_change": "92840d4624bb07440bb1ab5cb4b57251c9950388accbc8334a9a7d609ededb01",
"T3B1_cs_evolu-test_get_node.py::test_evolu_get_node_invalid_proof": "1aaf307e406fdd1cd3232ab62db7bf1437907afa1863f99bae65e8b9b66f5b45",
"T3B1_cs_evolu-test_get_node.py::test_evolu_get_node_no_proof": "92840d4624bb07440bb1ab5cb4b57251c9950388accbc8334a9a7d609ededb01",
"T3B1_cs_evolu-test_get_node.py::test_evolu_get_node_none_proof": "92840d4624bb07440bb1ab5cb4b57251c9950388accbc8334a9a7d609ededb01",
+"T3B1_cs_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-0]": "1aaf307e406fdd1cd3232ab62db7bf1437907afa1863f99bae65e8b9b66f5b45",
+"T3B1_cs_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-42]": "1aaf307e406fdd1cd3232ab62db7bf1437907afa1863f99bae65e8b9b66f5b45",
+"T3B1_cs_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-None]": "1aaf307e406fdd1cd3232ab62db7bf1437907afa1863f99bae65e8b9b66f5b45",
+"T3B1_cs_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-0]": "1aaf307e406fdd1cd3232ab62db7bf1437907afa1863f99bae65e8b9b66f5b45",
+"T3B1_cs_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-42]": "1aaf307e406fdd1cd3232ab62db7bf1437907afa1863f99bae65e8b9b66f5b45",
+"T3B1_cs_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-None]": "1aaf307e406fdd1cd3232ab62db7bf1437907afa1863f99bae65e8b9b66f5b45",
"T3B1_cs_evolu-test_sign_registration.py::test_evolu_sign_request": "78e068c30568e38df05db147e60378a939ea3d2d325f18aba0208c275333921b",
"T3B1_cs_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_long": "1aaf307e406fdd1cd3232ab62db7bf1437907afa1863f99bae65e8b9b66f5b45",
"T3B1_cs_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_short": "1aaf307e406fdd1cd3232ab62db7bf1437907afa1863f99bae65e8b9b66f5b45",
@@ -12437,6 +12563,11 @@
"T3B1_cs_evolu-test_sign_registration.py::test_evolu_sign_request_invalid_proof": "1aaf307e406fdd1cd3232ab62db7bf1437907afa1863f99bae65e8b9b66f5b45",
"T3B1_cs_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_large": "1aaf307e406fdd1cd3232ab62db7bf1437907afa1863f99bae65e8b9b66f5b45",
"T3B1_cs_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_small": "1aaf307e406fdd1cd3232ab62db7bf1437907afa1863f99bae65e8b9b66f5b45",
+"T3B1_cs_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[0]": "78e068c30568e38df05db147e60378a939ea3d2d325f18aba0208c275333921b",
+"T3B1_cs_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[1]": "78e068c30568e38df05db147e60378a939ea3d2d325f18aba0208c275333921b",
+"T3B1_cs_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[2]": "78e068c30568e38df05db147e60378a939ea3d2d325f18aba0208c275333921b",
+"T3B1_cs_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[42]": "78e068c30568e38df05db147e60378a939ea3d2d325f18aba0208c275333921b",
+"T3B1_cs_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[None]": "78e068c30568e38df05db147e60378a939ea3d2d325f18aba0208c275333921b",
"T3B1_cs_misc-test_msg_cipherkeyvalue.py::test_decrypt": "e3ae520cd3f8bc3f83584ef3faf41a8251d7577c687e42c8ed7eb73206c284e0",
"T3B1_cs_misc-test_msg_cipherkeyvalue.py::test_decrypt_badlen": "92840d4624bb07440bb1ab5cb4b57251c9950388accbc8334a9a7d609ededb01",
"T3B1_cs_misc-test_msg_cipherkeyvalue.py::test_encrypt": "dc5befa5c465a6a85394921d6593f4c0bd1b0c781b05b726c4de0b2d82cf0d89",
@@ -13992,13 +14123,31 @@
"T3B1_de_ethereum-test_signtx.py::test_signtx_staking_eip1559[stake_main]": "41a01e8a2794dc74760f158d73f9822f693b877c0f50235e878e8a62f0ab32fc",
"T3B1_de_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_hoodi]": "2d581c53427245a57e880ba15ce0b48bc34dedb31e11f393b47917e1faf773b4",
"T3B1_de_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_main]": "74d4aea32181321276131a9b57e0dc9ab2ea8fb4c82d560ff70152fd3ef6d313",
+"T3B1_de_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation": "afa5d433ee0e5b0f39e8544619c69c7ada617be7613394dd6cce07e7f2e4680f",
+"T3B1_de_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_index_increment": "af4e127cda4623e517634c80a3eb9c341c666b4c13dfbc020a3f354a65becc16",
+"T3B1_de_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_max_index": "c92ee4e050daadcfc7cc95657b00deed76bb463d486eefcc66455bdbe60faa33",
+"T3B1_de_evolu-test_delegated_identity_key_rotation.py::test_explicit_index_zero_on_uninitialized_device": "31c6f158bb70b118f68dd0715e31eb51537231d6e2aca824b9d959c97cd758d3",
+"T3B1_de_evolu-test_delegated_identity_key_rotation.py::test_first_rotation_index_is_None": "31c6f158bb70b118f68dd0715e31eb51537231d6e2aca824b9d959c97cd758d3",
+"T3B1_de_evolu-test_delegated_identity_key_rotation.py::test_index_management_cannot_overwrite_existing_index": "345ca8fb0e440cbb1f34c88b98acba6a665e9efb0c91ecbd2a373197cd1391d4",
+"T3B1_de_evolu-test_delegated_identity_key_rotation.py::test_index_management_getter": "c92ee4e050daadcfc7cc95657b00deed76bb463d486eefcc66455bdbe60faa33",
+"T3B1_de_evolu-test_delegated_identity_key_rotation.py::test_rotate_affects_index_management": "25e0f059d0dd341b745bec045dff378509d23a32d2a7b6cde0b7ad9f82d49ef2",
+"T3B1_de_evolu-test_delegated_identity_key_rotation.py::test_rotation_index_wiped_on_device_wipe": "75016a86c14abb1d1af607541a7484b93223be132329c3701f87a5f49c419120",
"T3B1_de_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_is_constant": "31c6f158bb70b118f68dd0715e31eb51537231d6e2aca824b9d959c97cd758d3",
"T3B1_de_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_test_vector": "345ca8fb0e440cbb1f34c88b98acba6a665e9efb0c91ecbd2a373197cd1391d4",
"T3B1_de_evolu-test_get_node.py::test_evolu_get_node": "345ca8fb0e440cbb1f34c88b98acba6a665e9efb0c91ecbd2a373197cd1391d4",
-"T3B1_de_evolu-test_get_node.py::test_evolu_get_node_different_seed": "345ca8fb0e440cbb1f34c88b98acba6a665e9efb0c91ecbd2a373197cd1391d4",
+"T3B1_de_evolu-test_get_node.py::test_evolu_get_node_different_seed[TREZOR]": "815d558140055a971d7e7c45781128522b0db5ce542c27ef4be65a1a0c5afa54",
+"T3B1_de_evolu-test_get_node.py::test_evolu_get_node_different_seed[]": "345ca8fb0e440cbb1f34c88b98acba6a665e9efb0c91ecbd2a373197cd1391d4",
+"T3B1_de_evolu-test_get_node.py::test_evolu_get_node_index_1": "c92ee4e050daadcfc7cc95657b00deed76bb463d486eefcc66455bdbe60faa33",
+"T3B1_de_evolu-test_get_node.py::test_evolu_get_node_index_change": "c92ee4e050daadcfc7cc95657b00deed76bb463d486eefcc66455bdbe60faa33",
"T3B1_de_evolu-test_get_node.py::test_evolu_get_node_invalid_proof": "345ca8fb0e440cbb1f34c88b98acba6a665e9efb0c91ecbd2a373197cd1391d4",
"T3B1_de_evolu-test_get_node.py::test_evolu_get_node_no_proof": "c92ee4e050daadcfc7cc95657b00deed76bb463d486eefcc66455bdbe60faa33",
"T3B1_de_evolu-test_get_node.py::test_evolu_get_node_none_proof": "c92ee4e050daadcfc7cc95657b00deed76bb463d486eefcc66455bdbe60faa33",
+"T3B1_de_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-0]": "345ca8fb0e440cbb1f34c88b98acba6a665e9efb0c91ecbd2a373197cd1391d4",
+"T3B1_de_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-42]": "345ca8fb0e440cbb1f34c88b98acba6a665e9efb0c91ecbd2a373197cd1391d4",
+"T3B1_de_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-None]": "345ca8fb0e440cbb1f34c88b98acba6a665e9efb0c91ecbd2a373197cd1391d4",
+"T3B1_de_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-0]": "345ca8fb0e440cbb1f34c88b98acba6a665e9efb0c91ecbd2a373197cd1391d4",
+"T3B1_de_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-42]": "345ca8fb0e440cbb1f34c88b98acba6a665e9efb0c91ecbd2a373197cd1391d4",
+"T3B1_de_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-None]": "345ca8fb0e440cbb1f34c88b98acba6a665e9efb0c91ecbd2a373197cd1391d4",
"T3B1_de_evolu-test_sign_registration.py::test_evolu_sign_request": "31c6f158bb70b118f68dd0715e31eb51537231d6e2aca824b9d959c97cd758d3",
"T3B1_de_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_long": "345ca8fb0e440cbb1f34c88b98acba6a665e9efb0c91ecbd2a373197cd1391d4",
"T3B1_de_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_short": "345ca8fb0e440cbb1f34c88b98acba6a665e9efb0c91ecbd2a373197cd1391d4",
@@ -14006,6 +14155,11 @@
"T3B1_de_evolu-test_sign_registration.py::test_evolu_sign_request_invalid_proof": "345ca8fb0e440cbb1f34c88b98acba6a665e9efb0c91ecbd2a373197cd1391d4",
"T3B1_de_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_large": "345ca8fb0e440cbb1f34c88b98acba6a665e9efb0c91ecbd2a373197cd1391d4",
"T3B1_de_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_small": "345ca8fb0e440cbb1f34c88b98acba6a665e9efb0c91ecbd2a373197cd1391d4",
+"T3B1_de_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[0]": "31c6f158bb70b118f68dd0715e31eb51537231d6e2aca824b9d959c97cd758d3",
+"T3B1_de_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[1]": "31c6f158bb70b118f68dd0715e31eb51537231d6e2aca824b9d959c97cd758d3",
+"T3B1_de_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[2]": "31c6f158bb70b118f68dd0715e31eb51537231d6e2aca824b9d959c97cd758d3",
+"T3B1_de_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[42]": "31c6f158bb70b118f68dd0715e31eb51537231d6e2aca824b9d959c97cd758d3",
+"T3B1_de_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[None]": "31c6f158bb70b118f68dd0715e31eb51537231d6e2aca824b9d959c97cd758d3",
"T3B1_de_misc-test_msg_cipherkeyvalue.py::test_decrypt": "1058dffae8d462d10aed9dad9ead0265f28f18cf014e9f428a236bd81065a721",
"T3B1_de_misc-test_msg_cipherkeyvalue.py::test_decrypt_badlen": "c92ee4e050daadcfc7cc95657b00deed76bb463d486eefcc66455bdbe60faa33",
"T3B1_de_misc-test_msg_cipherkeyvalue.py::test_encrypt": "c394c4a88e7f120b82d341ca1a77aae5d5a404cfb1e04fc5a552ff2abc37cc0e",
@@ -15561,13 +15715,31 @@
"T3B1_en_ethereum-test_signtx.py::test_signtx_staking_eip1559[stake_main]": "8094d22c42ad3a403913921228d7d59163ab569085797529ae16ace4b1a8a41e",
"T3B1_en_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_hoodi]": "0a478ee103e6be5c321db80ac88899aac6540a635d00af1ff2de61b91d92e0d9",
"T3B1_en_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_main]": "b742c1e25b0b84bf653409c06a1d6e4eb2ef8117da4528d835315bdb9920636e",
+"T3B1_en_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation": "4351de951d2cdfc9c8ecb656fc202ac8f0a1072770d784b93dc88341c4e45a9e",
+"T3B1_en_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_index_increment": "00ffcbe23906a505230dd2c9463124be6fb8b5e235a0068e2524aa89a19e9309",
+"T3B1_en_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_max_index": "1477d62e338f4d7c1bfac2fc5d2fc231218da5768666c11482dc1f83229506f3",
+"T3B1_en_evolu-test_delegated_identity_key_rotation.py::test_explicit_index_zero_on_uninitialized_device": "c6749638d05ff1cbad4be3ae6e0058c4a8e85c5004b1fd22ba113fde7a65040d",
+"T3B1_en_evolu-test_delegated_identity_key_rotation.py::test_first_rotation_index_is_None": "c6749638d05ff1cbad4be3ae6e0058c4a8e85c5004b1fd22ba113fde7a65040d",
+"T3B1_en_evolu-test_delegated_identity_key_rotation.py::test_index_management_cannot_overwrite_existing_index": "e2e36fbe9b202822d16a5fad5afa5ffb4d941bc6dce726f6dc4beeac9ef179e7",
+"T3B1_en_evolu-test_delegated_identity_key_rotation.py::test_index_management_getter": "1477d62e338f4d7c1bfac2fc5d2fc231218da5768666c11482dc1f83229506f3",
+"T3B1_en_evolu-test_delegated_identity_key_rotation.py::test_rotate_affects_index_management": "af14b03a68903d18348bd7ada8bb26d9a69f80629ec7dc9dbfdc98cd3386d367",
+"T3B1_en_evolu-test_delegated_identity_key_rotation.py::test_rotation_index_wiped_on_device_wipe": "0f279c521dfe056e785aa9b18c230cd464cdda26735a0c1bc3abb364044d6f8b",
"T3B1_en_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_is_constant": "c6749638d05ff1cbad4be3ae6e0058c4a8e85c5004b1fd22ba113fde7a65040d",
"T3B1_en_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_test_vector": "e2e36fbe9b202822d16a5fad5afa5ffb4d941bc6dce726f6dc4beeac9ef179e7",
"T3B1_en_evolu-test_get_node.py::test_evolu_get_node": "e2e36fbe9b202822d16a5fad5afa5ffb4d941bc6dce726f6dc4beeac9ef179e7",
-"T3B1_en_evolu-test_get_node.py::test_evolu_get_node_different_seed": "e2e36fbe9b202822d16a5fad5afa5ffb4d941bc6dce726f6dc4beeac9ef179e7",
+"T3B1_en_evolu-test_get_node.py::test_evolu_get_node_different_seed[TREZOR]": "ad214132ccb06f74e2d5f2a22623036a8d0be5ca1b2ef7a9fd8a463ed9272415",
+"T3B1_en_evolu-test_get_node.py::test_evolu_get_node_different_seed[]": "e2e36fbe9b202822d16a5fad5afa5ffb4d941bc6dce726f6dc4beeac9ef179e7",
+"T3B1_en_evolu-test_get_node.py::test_evolu_get_node_index_1": "1477d62e338f4d7c1bfac2fc5d2fc231218da5768666c11482dc1f83229506f3",
+"T3B1_en_evolu-test_get_node.py::test_evolu_get_node_index_change": "1477d62e338f4d7c1bfac2fc5d2fc231218da5768666c11482dc1f83229506f3",
"T3B1_en_evolu-test_get_node.py::test_evolu_get_node_invalid_proof": "e2e36fbe9b202822d16a5fad5afa5ffb4d941bc6dce726f6dc4beeac9ef179e7",
"T3B1_en_evolu-test_get_node.py::test_evolu_get_node_no_proof": "1477d62e338f4d7c1bfac2fc5d2fc231218da5768666c11482dc1f83229506f3",
"T3B1_en_evolu-test_get_node.py::test_evolu_get_node_none_proof": "1477d62e338f4d7c1bfac2fc5d2fc231218da5768666c11482dc1f83229506f3",
+"T3B1_en_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-0]": "e2e36fbe9b202822d16a5fad5afa5ffb4d941bc6dce726f6dc4beeac9ef179e7",
+"T3B1_en_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-42]": "e2e36fbe9b202822d16a5fad5afa5ffb4d941bc6dce726f6dc4beeac9ef179e7",
+"T3B1_en_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-None]": "e2e36fbe9b202822d16a5fad5afa5ffb4d941bc6dce726f6dc4beeac9ef179e7",
+"T3B1_en_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-0]": "e2e36fbe9b202822d16a5fad5afa5ffb4d941bc6dce726f6dc4beeac9ef179e7",
+"T3B1_en_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-42]": "e2e36fbe9b202822d16a5fad5afa5ffb4d941bc6dce726f6dc4beeac9ef179e7",
+"T3B1_en_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-None]": "e2e36fbe9b202822d16a5fad5afa5ffb4d941bc6dce726f6dc4beeac9ef179e7",
"T3B1_en_evolu-test_sign_registration.py::test_evolu_sign_request": "c6749638d05ff1cbad4be3ae6e0058c4a8e85c5004b1fd22ba113fde7a65040d",
"T3B1_en_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_long": "e2e36fbe9b202822d16a5fad5afa5ffb4d941bc6dce726f6dc4beeac9ef179e7",
"T3B1_en_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_short": "e2e36fbe9b202822d16a5fad5afa5ffb4d941bc6dce726f6dc4beeac9ef179e7",
@@ -15575,6 +15747,11 @@
"T3B1_en_evolu-test_sign_registration.py::test_evolu_sign_request_invalid_proof": "e2e36fbe9b202822d16a5fad5afa5ffb4d941bc6dce726f6dc4beeac9ef179e7",
"T3B1_en_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_large": "e2e36fbe9b202822d16a5fad5afa5ffb4d941bc6dce726f6dc4beeac9ef179e7",
"T3B1_en_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_small": "e2e36fbe9b202822d16a5fad5afa5ffb4d941bc6dce726f6dc4beeac9ef179e7",
+"T3B1_en_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[0]": "c6749638d05ff1cbad4be3ae6e0058c4a8e85c5004b1fd22ba113fde7a65040d",
+"T3B1_en_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[1]": "c6749638d05ff1cbad4be3ae6e0058c4a8e85c5004b1fd22ba113fde7a65040d",
+"T3B1_en_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[2]": "c6749638d05ff1cbad4be3ae6e0058c4a8e85c5004b1fd22ba113fde7a65040d",
+"T3B1_en_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[42]": "c6749638d05ff1cbad4be3ae6e0058c4a8e85c5004b1fd22ba113fde7a65040d",
+"T3B1_en_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[None]": "c6749638d05ff1cbad4be3ae6e0058c4a8e85c5004b1fd22ba113fde7a65040d",
"T3B1_en_misc-test_msg_cipherkeyvalue.py::test_decrypt": "64fcfa249a4d36367f5da39e023d9bf3c193469a986d45c64d2cf3ac2f574774",
"T3B1_en_misc-test_msg_cipherkeyvalue.py::test_decrypt_badlen": "1477d62e338f4d7c1bfac2fc5d2fc231218da5768666c11482dc1f83229506f3",
"T3B1_en_misc-test_msg_cipherkeyvalue.py::test_encrypt": "e2a9a7e518de0ef49f5bcbaa87f8558483fc5ca5527141b629b3fbc6ab33faa7",
@@ -17130,13 +17307,31 @@
"T3B1_es_ethereum-test_signtx.py::test_signtx_staking_eip1559[stake_main]": "fc573adee125d6cb4ac8e752a0575e97147129742e617b9423cf461455d348f0",
"T3B1_es_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_hoodi]": "c45d57bfa8bc21ef764893603dd2045a7100ae43a9a36f472bb6de9618c95b99",
"T3B1_es_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_main]": "5145c5edc292d516fde054ba891dff7f86fcc0fa1e99fc05d36458339593e7a2",
+"T3B1_es_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation": "326ed362bd5671b8d6d9d70955f06627822b32aa1de6632eead5d74f2fd6f20e",
+"T3B1_es_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_index_increment": "cee2423010bfb54b55b2f0eb9aa69c42176176bc5e3236d71c4130abe9aa6f52",
+"T3B1_es_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_max_index": "211e7c3419bd48ceefc570971fc522f809b39614563be948fd1e545366506dee",
+"T3B1_es_evolu-test_delegated_identity_key_rotation.py::test_explicit_index_zero_on_uninitialized_device": "d1a7e0a66a35119ec38747f8712000842b002a42277020f490bfe22054d862d8",
+"T3B1_es_evolu-test_delegated_identity_key_rotation.py::test_first_rotation_index_is_None": "d1a7e0a66a35119ec38747f8712000842b002a42277020f490bfe22054d862d8",
+"T3B1_es_evolu-test_delegated_identity_key_rotation.py::test_index_management_cannot_overwrite_existing_index": "fa9d06102cb8758b6cd384f672aaf3b859a16ca55543db4280a79e58ffd89013",
+"T3B1_es_evolu-test_delegated_identity_key_rotation.py::test_index_management_getter": "211e7c3419bd48ceefc570971fc522f809b39614563be948fd1e545366506dee",
+"T3B1_es_evolu-test_delegated_identity_key_rotation.py::test_rotate_affects_index_management": "7a2aff78263f02e02b223133505b67cb86ea566497a2d78c8f84d2af63e66be0",
+"T3B1_es_evolu-test_delegated_identity_key_rotation.py::test_rotation_index_wiped_on_device_wipe": "b3e6a66490062bd64d517fa4b5b902d92f9c29bfc18957287cfa01803b173824",
"T3B1_es_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_is_constant": "d1a7e0a66a35119ec38747f8712000842b002a42277020f490bfe22054d862d8",
"T3B1_es_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_test_vector": "fa9d06102cb8758b6cd384f672aaf3b859a16ca55543db4280a79e58ffd89013",
"T3B1_es_evolu-test_get_node.py::test_evolu_get_node": "fa9d06102cb8758b6cd384f672aaf3b859a16ca55543db4280a79e58ffd89013",
-"T3B1_es_evolu-test_get_node.py::test_evolu_get_node_different_seed": "fa9d06102cb8758b6cd384f672aaf3b859a16ca55543db4280a79e58ffd89013",
+"T3B1_es_evolu-test_get_node.py::test_evolu_get_node_different_seed[TREZOR]": "6a1c4db6558dc4b90faf08d4a652c97d2758d4ed11122bcaafe4227a3084e20c",
+"T3B1_es_evolu-test_get_node.py::test_evolu_get_node_different_seed[]": "fa9d06102cb8758b6cd384f672aaf3b859a16ca55543db4280a79e58ffd89013",
+"T3B1_es_evolu-test_get_node.py::test_evolu_get_node_index_1": "211e7c3419bd48ceefc570971fc522f809b39614563be948fd1e545366506dee",
+"T3B1_es_evolu-test_get_node.py::test_evolu_get_node_index_change": "211e7c3419bd48ceefc570971fc522f809b39614563be948fd1e545366506dee",
"T3B1_es_evolu-test_get_node.py::test_evolu_get_node_invalid_proof": "fa9d06102cb8758b6cd384f672aaf3b859a16ca55543db4280a79e58ffd89013",
"T3B1_es_evolu-test_get_node.py::test_evolu_get_node_no_proof": "211e7c3419bd48ceefc570971fc522f809b39614563be948fd1e545366506dee",
"T3B1_es_evolu-test_get_node.py::test_evolu_get_node_none_proof": "211e7c3419bd48ceefc570971fc522f809b39614563be948fd1e545366506dee",
+"T3B1_es_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-0]": "fa9d06102cb8758b6cd384f672aaf3b859a16ca55543db4280a79e58ffd89013",
+"T3B1_es_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-42]": "fa9d06102cb8758b6cd384f672aaf3b859a16ca55543db4280a79e58ffd89013",
+"T3B1_es_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-None]": "fa9d06102cb8758b6cd384f672aaf3b859a16ca55543db4280a79e58ffd89013",
+"T3B1_es_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-0]": "fa9d06102cb8758b6cd384f672aaf3b859a16ca55543db4280a79e58ffd89013",
+"T3B1_es_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-42]": "fa9d06102cb8758b6cd384f672aaf3b859a16ca55543db4280a79e58ffd89013",
+"T3B1_es_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-None]": "fa9d06102cb8758b6cd384f672aaf3b859a16ca55543db4280a79e58ffd89013",
"T3B1_es_evolu-test_sign_registration.py::test_evolu_sign_request": "d1a7e0a66a35119ec38747f8712000842b002a42277020f490bfe22054d862d8",
"T3B1_es_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_long": "fa9d06102cb8758b6cd384f672aaf3b859a16ca55543db4280a79e58ffd89013",
"T3B1_es_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_short": "fa9d06102cb8758b6cd384f672aaf3b859a16ca55543db4280a79e58ffd89013",
@@ -17144,6 +17339,11 @@
"T3B1_es_evolu-test_sign_registration.py::test_evolu_sign_request_invalid_proof": "fa9d06102cb8758b6cd384f672aaf3b859a16ca55543db4280a79e58ffd89013",
"T3B1_es_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_large": "fa9d06102cb8758b6cd384f672aaf3b859a16ca55543db4280a79e58ffd89013",
"T3B1_es_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_small": "fa9d06102cb8758b6cd384f672aaf3b859a16ca55543db4280a79e58ffd89013",
+"T3B1_es_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[0]": "d1a7e0a66a35119ec38747f8712000842b002a42277020f490bfe22054d862d8",
+"T3B1_es_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[1]": "d1a7e0a66a35119ec38747f8712000842b002a42277020f490bfe22054d862d8",
+"T3B1_es_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[2]": "d1a7e0a66a35119ec38747f8712000842b002a42277020f490bfe22054d862d8",
+"T3B1_es_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[42]": "d1a7e0a66a35119ec38747f8712000842b002a42277020f490bfe22054d862d8",
+"T3B1_es_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[None]": "d1a7e0a66a35119ec38747f8712000842b002a42277020f490bfe22054d862d8",
"T3B1_es_misc-test_msg_cipherkeyvalue.py::test_decrypt": "a05c508711633695591fd4be906bcff4ce5e1deba2340830b8453fabc435c4c0",
"T3B1_es_misc-test_msg_cipherkeyvalue.py::test_decrypt_badlen": "211e7c3419bd48ceefc570971fc522f809b39614563be948fd1e545366506dee",
"T3B1_es_misc-test_msg_cipherkeyvalue.py::test_encrypt": "f9f520f956b5f4970d6c6ae4cceca3f53cfeeb26f1919d18d7405a5a6f8dd649",
@@ -18699,13 +18899,31 @@
"T3B1_fr_ethereum-test_signtx.py::test_signtx_staking_eip1559[stake_main]": "748725945a6ed3030c9d7b222691780c529e94cf9409e4aa4a373a61430e606d",
"T3B1_fr_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_hoodi]": "9552b31acbf85334d6369905fa3723bd2a66d0c22b6df0a2f8f84c76e295cef8",
"T3B1_fr_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_main]": "fb20021587c81313e03aa24fd738ca35196c1025bae9bca4ce10d0bf57376773",
+"T3B1_fr_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation": "3b5cb5d272dde80f8e91dd8d0e283b177e7818ad73554de55aa9d1e7a82f5132",
+"T3B1_fr_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_index_increment": "30191a911bdb43b7224deb16e8b098284ad1c259338451c08f174ed848366a91",
+"T3B1_fr_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_max_index": "35c9c9529c59ca5c386ac05856f7452f26cde732203b5b61ec9321230b52df89",
+"T3B1_fr_evolu-test_delegated_identity_key_rotation.py::test_explicit_index_zero_on_uninitialized_device": "5de68c9c94abc1623a218ac4cb27ed328d8104c3ffb70146d39e680e305f3af7",
+"T3B1_fr_evolu-test_delegated_identity_key_rotation.py::test_first_rotation_index_is_None": "5de68c9c94abc1623a218ac4cb27ed328d8104c3ffb70146d39e680e305f3af7",
+"T3B1_fr_evolu-test_delegated_identity_key_rotation.py::test_index_management_cannot_overwrite_existing_index": "c365666f6c395de12f9d413ff2fd923c283e68248d3fef8bd0a1ec745e4fcd02",
+"T3B1_fr_evolu-test_delegated_identity_key_rotation.py::test_index_management_getter": "35c9c9529c59ca5c386ac05856f7452f26cde732203b5b61ec9321230b52df89",
+"T3B1_fr_evolu-test_delegated_identity_key_rotation.py::test_rotate_affects_index_management": "773ea3292e106acf53b91683745d84fd176cc28d4b2966fec0ef398b5a38cc4a",
+"T3B1_fr_evolu-test_delegated_identity_key_rotation.py::test_rotation_index_wiped_on_device_wipe": "c9d2e77f67899bd9e55ef8879a945423e70be727612ad788a33cae3e159d2e41",
"T3B1_fr_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_is_constant": "5de68c9c94abc1623a218ac4cb27ed328d8104c3ffb70146d39e680e305f3af7",
"T3B1_fr_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_test_vector": "c365666f6c395de12f9d413ff2fd923c283e68248d3fef8bd0a1ec745e4fcd02",
"T3B1_fr_evolu-test_get_node.py::test_evolu_get_node": "c365666f6c395de12f9d413ff2fd923c283e68248d3fef8bd0a1ec745e4fcd02",
-"T3B1_fr_evolu-test_get_node.py::test_evolu_get_node_different_seed": "c365666f6c395de12f9d413ff2fd923c283e68248d3fef8bd0a1ec745e4fcd02",
+"T3B1_fr_evolu-test_get_node.py::test_evolu_get_node_different_seed[TREZOR]": "b5e2ac354c48bf5540df9cedf16f4210c85933a4d9663847bd0d273e89a61f2f",
+"T3B1_fr_evolu-test_get_node.py::test_evolu_get_node_different_seed[]": "c365666f6c395de12f9d413ff2fd923c283e68248d3fef8bd0a1ec745e4fcd02",
+"T3B1_fr_evolu-test_get_node.py::test_evolu_get_node_index_1": "35c9c9529c59ca5c386ac05856f7452f26cde732203b5b61ec9321230b52df89",
+"T3B1_fr_evolu-test_get_node.py::test_evolu_get_node_index_change": "35c9c9529c59ca5c386ac05856f7452f26cde732203b5b61ec9321230b52df89",
"T3B1_fr_evolu-test_get_node.py::test_evolu_get_node_invalid_proof": "c365666f6c395de12f9d413ff2fd923c283e68248d3fef8bd0a1ec745e4fcd02",
"T3B1_fr_evolu-test_get_node.py::test_evolu_get_node_no_proof": "35c9c9529c59ca5c386ac05856f7452f26cde732203b5b61ec9321230b52df89",
"T3B1_fr_evolu-test_get_node.py::test_evolu_get_node_none_proof": "35c9c9529c59ca5c386ac05856f7452f26cde732203b5b61ec9321230b52df89",
+"T3B1_fr_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-0]": "c365666f6c395de12f9d413ff2fd923c283e68248d3fef8bd0a1ec745e4fcd02",
+"T3B1_fr_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-42]": "c365666f6c395de12f9d413ff2fd923c283e68248d3fef8bd0a1ec745e4fcd02",
+"T3B1_fr_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-None]": "c365666f6c395de12f9d413ff2fd923c283e68248d3fef8bd0a1ec745e4fcd02",
+"T3B1_fr_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-0]": "c365666f6c395de12f9d413ff2fd923c283e68248d3fef8bd0a1ec745e4fcd02",
+"T3B1_fr_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-42]": "c365666f6c395de12f9d413ff2fd923c283e68248d3fef8bd0a1ec745e4fcd02",
+"T3B1_fr_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-None]": "c365666f6c395de12f9d413ff2fd923c283e68248d3fef8bd0a1ec745e4fcd02",
"T3B1_fr_evolu-test_sign_registration.py::test_evolu_sign_request": "5de68c9c94abc1623a218ac4cb27ed328d8104c3ffb70146d39e680e305f3af7",
"T3B1_fr_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_long": "c365666f6c395de12f9d413ff2fd923c283e68248d3fef8bd0a1ec745e4fcd02",
"T3B1_fr_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_short": "c365666f6c395de12f9d413ff2fd923c283e68248d3fef8bd0a1ec745e4fcd02",
@@ -18713,6 +18931,11 @@
"T3B1_fr_evolu-test_sign_registration.py::test_evolu_sign_request_invalid_proof": "c365666f6c395de12f9d413ff2fd923c283e68248d3fef8bd0a1ec745e4fcd02",
"T3B1_fr_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_large": "c365666f6c395de12f9d413ff2fd923c283e68248d3fef8bd0a1ec745e4fcd02",
"T3B1_fr_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_small": "c365666f6c395de12f9d413ff2fd923c283e68248d3fef8bd0a1ec745e4fcd02",
+"T3B1_fr_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[0]": "5de68c9c94abc1623a218ac4cb27ed328d8104c3ffb70146d39e680e305f3af7",
+"T3B1_fr_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[1]": "5de68c9c94abc1623a218ac4cb27ed328d8104c3ffb70146d39e680e305f3af7",
+"T3B1_fr_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[2]": "5de68c9c94abc1623a218ac4cb27ed328d8104c3ffb70146d39e680e305f3af7",
+"T3B1_fr_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[42]": "5de68c9c94abc1623a218ac4cb27ed328d8104c3ffb70146d39e680e305f3af7",
+"T3B1_fr_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[None]": "5de68c9c94abc1623a218ac4cb27ed328d8104c3ffb70146d39e680e305f3af7",
"T3B1_fr_misc-test_msg_cipherkeyvalue.py::test_decrypt": "3f82eafa72fcdcfddcadf6d2d6e832648f359eada9d626fb5d7ca766e15a4943",
"T3B1_fr_misc-test_msg_cipherkeyvalue.py::test_decrypt_badlen": "35c9c9529c59ca5c386ac05856f7452f26cde732203b5b61ec9321230b52df89",
"T3B1_fr_misc-test_msg_cipherkeyvalue.py::test_encrypt": "88535c0209a4702c1b93d70158cdebea78c781e0819e543400be5491af172cca",
@@ -20268,13 +20491,31 @@
"T3B1_pt_ethereum-test_signtx.py::test_signtx_staking_eip1559[stake_main]": "722246b2e0929ee050c8ad9736543aa553e7ff76ff064fe4f9b70fb631aa7568",
"T3B1_pt_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_hoodi]": "b9ad2f1d129ff6ba66b4085fab9f17a53178da0287365c74185ccd71907e2e92",
"T3B1_pt_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_main]": "90105f8279ee17a7b28e0788618989bea8f01897652247b454591769abec9ccc",
+"T3B1_pt_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation": "7ca22931af45b4193bdb99e1f95c9488a1a8d9eee62062894f8667546facd15d",
+"T3B1_pt_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_index_increment": "2af4d85cb4f0de490f6b14b7e9b3d551a0127a36e32f070aada89a0086ec57fc",
+"T3B1_pt_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_max_index": "6ba5ca7223cd8ad675e081407f186acdfc8420304eea96de0fde5eda45ef0a57",
+"T3B1_pt_evolu-test_delegated_identity_key_rotation.py::test_explicit_index_zero_on_uninitialized_device": "700aec004938cd32abc286d0479fd67203093a20af05f681f4212e937527df77",
+"T3B1_pt_evolu-test_delegated_identity_key_rotation.py::test_first_rotation_index_is_None": "700aec004938cd32abc286d0479fd67203093a20af05f681f4212e937527df77",
+"T3B1_pt_evolu-test_delegated_identity_key_rotation.py::test_index_management_cannot_overwrite_existing_index": "15b940e8cf8c01a420d1673ed761f44882a5566709fcdd188f3b10381d66422c",
+"T3B1_pt_evolu-test_delegated_identity_key_rotation.py::test_index_management_getter": "6ba5ca7223cd8ad675e081407f186acdfc8420304eea96de0fde5eda45ef0a57",
+"T3B1_pt_evolu-test_delegated_identity_key_rotation.py::test_rotate_affects_index_management": "6516b3df353b310d5f3c6ff762b5b412c0bbd5d388e2ffb83ea24ad447863c93",
+"T3B1_pt_evolu-test_delegated_identity_key_rotation.py::test_rotation_index_wiped_on_device_wipe": "94d21291fe62d34c1334555f82936c8ae3d6258202d6c6b520242c1ed7653435",
"T3B1_pt_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_is_constant": "700aec004938cd32abc286d0479fd67203093a20af05f681f4212e937527df77",
"T3B1_pt_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_test_vector": "15b940e8cf8c01a420d1673ed761f44882a5566709fcdd188f3b10381d66422c",
"T3B1_pt_evolu-test_get_node.py::test_evolu_get_node": "15b940e8cf8c01a420d1673ed761f44882a5566709fcdd188f3b10381d66422c",
-"T3B1_pt_evolu-test_get_node.py::test_evolu_get_node_different_seed": "15b940e8cf8c01a420d1673ed761f44882a5566709fcdd188f3b10381d66422c",
+"T3B1_pt_evolu-test_get_node.py::test_evolu_get_node_different_seed[TREZOR]": "a122631a54d3352b6c9fc045ec6dfd84b73093f7f509008d6921d6880b9f1e9c",
+"T3B1_pt_evolu-test_get_node.py::test_evolu_get_node_different_seed[]": "15b940e8cf8c01a420d1673ed761f44882a5566709fcdd188f3b10381d66422c",
+"T3B1_pt_evolu-test_get_node.py::test_evolu_get_node_index_1": "6ba5ca7223cd8ad675e081407f186acdfc8420304eea96de0fde5eda45ef0a57",
+"T3B1_pt_evolu-test_get_node.py::test_evolu_get_node_index_change": "6ba5ca7223cd8ad675e081407f186acdfc8420304eea96de0fde5eda45ef0a57",
"T3B1_pt_evolu-test_get_node.py::test_evolu_get_node_invalid_proof": "15b940e8cf8c01a420d1673ed761f44882a5566709fcdd188f3b10381d66422c",
"T3B1_pt_evolu-test_get_node.py::test_evolu_get_node_no_proof": "6ba5ca7223cd8ad675e081407f186acdfc8420304eea96de0fde5eda45ef0a57",
"T3B1_pt_evolu-test_get_node.py::test_evolu_get_node_none_proof": "6ba5ca7223cd8ad675e081407f186acdfc8420304eea96de0fde5eda45ef0a57",
+"T3B1_pt_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-0]": "15b940e8cf8c01a420d1673ed761f44882a5566709fcdd188f3b10381d66422c",
+"T3B1_pt_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-42]": "15b940e8cf8c01a420d1673ed761f44882a5566709fcdd188f3b10381d66422c",
+"T3B1_pt_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-None]": "15b940e8cf8c01a420d1673ed761f44882a5566709fcdd188f3b10381d66422c",
+"T3B1_pt_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-0]": "15b940e8cf8c01a420d1673ed761f44882a5566709fcdd188f3b10381d66422c",
+"T3B1_pt_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-42]": "15b940e8cf8c01a420d1673ed761f44882a5566709fcdd188f3b10381d66422c",
+"T3B1_pt_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-None]": "15b940e8cf8c01a420d1673ed761f44882a5566709fcdd188f3b10381d66422c",
"T3B1_pt_evolu-test_sign_registration.py::test_evolu_sign_request": "700aec004938cd32abc286d0479fd67203093a20af05f681f4212e937527df77",
"T3B1_pt_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_long": "15b940e8cf8c01a420d1673ed761f44882a5566709fcdd188f3b10381d66422c",
"T3B1_pt_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_short": "15b940e8cf8c01a420d1673ed761f44882a5566709fcdd188f3b10381d66422c",
@@ -20282,6 +20523,11 @@
"T3B1_pt_evolu-test_sign_registration.py::test_evolu_sign_request_invalid_proof": "15b940e8cf8c01a420d1673ed761f44882a5566709fcdd188f3b10381d66422c",
"T3B1_pt_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_large": "15b940e8cf8c01a420d1673ed761f44882a5566709fcdd188f3b10381d66422c",
"T3B1_pt_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_small": "15b940e8cf8c01a420d1673ed761f44882a5566709fcdd188f3b10381d66422c",
+"T3B1_pt_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[0]": "700aec004938cd32abc286d0479fd67203093a20af05f681f4212e937527df77",
+"T3B1_pt_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[1]": "700aec004938cd32abc286d0479fd67203093a20af05f681f4212e937527df77",
+"T3B1_pt_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[2]": "700aec004938cd32abc286d0479fd67203093a20af05f681f4212e937527df77",
+"T3B1_pt_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[42]": "700aec004938cd32abc286d0479fd67203093a20af05f681f4212e937527df77",
+"T3B1_pt_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[None]": "700aec004938cd32abc286d0479fd67203093a20af05f681f4212e937527df77",
"T3B1_pt_misc-test_msg_cipherkeyvalue.py::test_decrypt": "d407036ac60cea24dd72098ad545ff95414b37f3a8d74c8f3cf80432239c1ed7",
"T3B1_pt_misc-test_msg_cipherkeyvalue.py::test_decrypt_badlen": "6ba5ca7223cd8ad675e081407f186acdfc8420304eea96de0fde5eda45ef0a57",
"T3B1_pt_misc-test_msg_cipherkeyvalue.py::test_encrypt": "f2a9d00da07b51cf977ecf6ef71a232c754d28ce5818a322769e111f8acc099f",
@@ -22231,13 +22477,31 @@
"T3T1_cs_ethereum-test_signtx.py::test_signtx_staking_eip1559[stake_main]": "2ca378d74ea6e665f2227ecad19d7479b8358e949727bf9b8c8f9c623f04c1dc",
"T3T1_cs_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_hoodi]": "c1af93a47b69d9f72a76f15f215b8c175a18869510ed439e62e20233292df672",
"T3T1_cs_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_main]": "1253afcc6758fac3e346149bca337dd74a8b86e518fe745af31e9c8a443f2a8e",
+"T3T1_cs_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation": "578c1ece8778b1b6598d19f0a3de3de64f1f507ec92483e06272b04b1850ea5d",
+"T3T1_cs_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_index_increment": "d72bc88a57da49369aeee20078a22cb3c7b7d93726a1229df67f3f6c4cb27248",
+"T3T1_cs_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_max_index": "592adf9c06f8f39132298b46037dd524fac99e58237a0c023197bf47df67d632",
+"T3T1_cs_evolu-test_delegated_identity_key_rotation.py::test_explicit_index_zero_on_uninitialized_device": "4447d3166fd84cb8d27cf23a64e34467945e7e82314f27b1d3cfee7f95fb4b5f",
+"T3T1_cs_evolu-test_delegated_identity_key_rotation.py::test_first_rotation_index_is_None": "4447d3166fd84cb8d27cf23a64e34467945e7e82314f27b1d3cfee7f95fb4b5f",
+"T3T1_cs_evolu-test_delegated_identity_key_rotation.py::test_index_management_cannot_overwrite_existing_index": "0ea11d9bc00c3009ca3cfd659c682ecf47ed0695bbf1144d17cc8651b0666cdb",
+"T3T1_cs_evolu-test_delegated_identity_key_rotation.py::test_index_management_getter": "592adf9c06f8f39132298b46037dd524fac99e58237a0c023197bf47df67d632",
+"T3T1_cs_evolu-test_delegated_identity_key_rotation.py::test_rotate_affects_index_management": "904db2cb465b470e771e54728fc5ebcc11825c05973325c236f2adf2f1918a8d",
+"T3T1_cs_evolu-test_delegated_identity_key_rotation.py::test_rotation_index_wiped_on_device_wipe": "249734fd96881d774b2e875f63aa5c2043f1f9bfa00e4a1be383a357f6937d76",
"T3T1_cs_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_is_constant": "4447d3166fd84cb8d27cf23a64e34467945e7e82314f27b1d3cfee7f95fb4b5f",
"T3T1_cs_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_test_vector": "0ea11d9bc00c3009ca3cfd659c682ecf47ed0695bbf1144d17cc8651b0666cdb",
"T3T1_cs_evolu-test_get_node.py::test_evolu_get_node": "0ea11d9bc00c3009ca3cfd659c682ecf47ed0695bbf1144d17cc8651b0666cdb",
-"T3T1_cs_evolu-test_get_node.py::test_evolu_get_node_different_seed": "0ea11d9bc00c3009ca3cfd659c682ecf47ed0695bbf1144d17cc8651b0666cdb",
+"T3T1_cs_evolu-test_get_node.py::test_evolu_get_node_different_seed[TREZOR]": "6ac38ef7621e32aa7688489753971dd8363b96b9266ed4927f4116d62ace1f2e",
+"T3T1_cs_evolu-test_get_node.py::test_evolu_get_node_different_seed[]": "0ea11d9bc00c3009ca3cfd659c682ecf47ed0695bbf1144d17cc8651b0666cdb",
+"T3T1_cs_evolu-test_get_node.py::test_evolu_get_node_index_1": "592adf9c06f8f39132298b46037dd524fac99e58237a0c023197bf47df67d632",
+"T3T1_cs_evolu-test_get_node.py::test_evolu_get_node_index_change": "592adf9c06f8f39132298b46037dd524fac99e58237a0c023197bf47df67d632",
"T3T1_cs_evolu-test_get_node.py::test_evolu_get_node_invalid_proof": "0ea11d9bc00c3009ca3cfd659c682ecf47ed0695bbf1144d17cc8651b0666cdb",
"T3T1_cs_evolu-test_get_node.py::test_evolu_get_node_no_proof": "592adf9c06f8f39132298b46037dd524fac99e58237a0c023197bf47df67d632",
"T3T1_cs_evolu-test_get_node.py::test_evolu_get_node_none_proof": "592adf9c06f8f39132298b46037dd524fac99e58237a0c023197bf47df67d632",
+"T3T1_cs_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-0]": "0ea11d9bc00c3009ca3cfd659c682ecf47ed0695bbf1144d17cc8651b0666cdb",
+"T3T1_cs_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-42]": "0ea11d9bc00c3009ca3cfd659c682ecf47ed0695bbf1144d17cc8651b0666cdb",
+"T3T1_cs_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-None]": "0ea11d9bc00c3009ca3cfd659c682ecf47ed0695bbf1144d17cc8651b0666cdb",
+"T3T1_cs_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-0]": "0ea11d9bc00c3009ca3cfd659c682ecf47ed0695bbf1144d17cc8651b0666cdb",
+"T3T1_cs_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-42]": "0ea11d9bc00c3009ca3cfd659c682ecf47ed0695bbf1144d17cc8651b0666cdb",
+"T3T1_cs_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-None]": "0ea11d9bc00c3009ca3cfd659c682ecf47ed0695bbf1144d17cc8651b0666cdb",
"T3T1_cs_evolu-test_sign_registration.py::test_evolu_sign_request": "4447d3166fd84cb8d27cf23a64e34467945e7e82314f27b1d3cfee7f95fb4b5f",
"T3T1_cs_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_long": "0ea11d9bc00c3009ca3cfd659c682ecf47ed0695bbf1144d17cc8651b0666cdb",
"T3T1_cs_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_short": "0ea11d9bc00c3009ca3cfd659c682ecf47ed0695bbf1144d17cc8651b0666cdb",
@@ -22245,6 +22509,11 @@
"T3T1_cs_evolu-test_sign_registration.py::test_evolu_sign_request_invalid_proof": "0ea11d9bc00c3009ca3cfd659c682ecf47ed0695bbf1144d17cc8651b0666cdb",
"T3T1_cs_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_large": "0ea11d9bc00c3009ca3cfd659c682ecf47ed0695bbf1144d17cc8651b0666cdb",
"T3T1_cs_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_small": "0ea11d9bc00c3009ca3cfd659c682ecf47ed0695bbf1144d17cc8651b0666cdb",
+"T3T1_cs_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[0]": "4447d3166fd84cb8d27cf23a64e34467945e7e82314f27b1d3cfee7f95fb4b5f",
+"T3T1_cs_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[1]": "4447d3166fd84cb8d27cf23a64e34467945e7e82314f27b1d3cfee7f95fb4b5f",
+"T3T1_cs_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[2]": "4447d3166fd84cb8d27cf23a64e34467945e7e82314f27b1d3cfee7f95fb4b5f",
+"T3T1_cs_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[42]": "4447d3166fd84cb8d27cf23a64e34467945e7e82314f27b1d3cfee7f95fb4b5f",
+"T3T1_cs_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[None]": "4447d3166fd84cb8d27cf23a64e34467945e7e82314f27b1d3cfee7f95fb4b5f",
"T3T1_cs_misc-test_msg_cipherkeyvalue.py::test_decrypt": "341bc9710eb01929b9442a93d4e7ca1de179a7d42fb6d557c6933daa4bc99dc3",
"T3T1_cs_misc-test_msg_cipherkeyvalue.py::test_decrypt_badlen": "592adf9c06f8f39132298b46037dd524fac99e58237a0c023197bf47df67d632",
"T3T1_cs_misc-test_msg_cipherkeyvalue.py::test_encrypt": "209b7a64596583ed0d9288d1458ed3ac1396d2d0eba69d87f4f6dc6305080fc1",
@@ -23833,13 +24102,31 @@
"T3T1_de_ethereum-test_signtx.py::test_signtx_staking_eip1559[stake_main]": "90b69082246be128866fcaca2f054a0b5460b485dc8eb21b2286f5fba1028fe1",
"T3T1_de_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_hoodi]": "0eb95aa8f69929a56481ebab26f61d7e435a674221b1db4c1dfcebe93f816651",
"T3T1_de_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_main]": "b95403a414c262995c0943db609b51e2d1e345db05f8e5f3a44e6cf97f25e06d",
+"T3T1_de_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation": "cbc7f7ab306c041610faaa59bc457345ccd02ff29d4fcfb19c97ac72a23f79b0",
+"T3T1_de_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_index_increment": "f926dcf68277c6598563ab8303b28994c190e067ac21a53ceaa9cea7cc7f94a2",
+"T3T1_de_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_max_index": "f2fcbbd7ad83aff9adc0ee97fe98e7272d8bcfcc4a023798e2ab1c9895fda70f",
+"T3T1_de_evolu-test_delegated_identity_key_rotation.py::test_explicit_index_zero_on_uninitialized_device": "3ff7f28441ede54b92b110ae2a62e1449bec22c21875fcb9882f140c88fd9761",
+"T3T1_de_evolu-test_delegated_identity_key_rotation.py::test_first_rotation_index_is_None": "3ff7f28441ede54b92b110ae2a62e1449bec22c21875fcb9882f140c88fd9761",
+"T3T1_de_evolu-test_delegated_identity_key_rotation.py::test_index_management_cannot_overwrite_existing_index": "5b317453116a865f6f2ac52fa8ba198168a9f0a4e592fbb90f93a82516766da9",
+"T3T1_de_evolu-test_delegated_identity_key_rotation.py::test_index_management_getter": "f2fcbbd7ad83aff9adc0ee97fe98e7272d8bcfcc4a023798e2ab1c9895fda70f",
+"T3T1_de_evolu-test_delegated_identity_key_rotation.py::test_rotate_affects_index_management": "df65c10dff1c01bee86c493c7bf1ff4b584916f07d1a7a60ea0687b876d31dc9",
+"T3T1_de_evolu-test_delegated_identity_key_rotation.py::test_rotation_index_wiped_on_device_wipe": "eaff6873d82c502a7d27933878529b3febf788ecad0ccd5ca73b535648c29175",
"T3T1_de_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_is_constant": "3ff7f28441ede54b92b110ae2a62e1449bec22c21875fcb9882f140c88fd9761",
"T3T1_de_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_test_vector": "5b317453116a865f6f2ac52fa8ba198168a9f0a4e592fbb90f93a82516766da9",
"T3T1_de_evolu-test_get_node.py::test_evolu_get_node": "5b317453116a865f6f2ac52fa8ba198168a9f0a4e592fbb90f93a82516766da9",
-"T3T1_de_evolu-test_get_node.py::test_evolu_get_node_different_seed": "5b317453116a865f6f2ac52fa8ba198168a9f0a4e592fbb90f93a82516766da9",
+"T3T1_de_evolu-test_get_node.py::test_evolu_get_node_different_seed[TREZOR]": "6d99aeb288438440dd6ff9166dabe256c366b01f48d10f0307d8849d1344a5ea",
+"T3T1_de_evolu-test_get_node.py::test_evolu_get_node_different_seed[]": "5b317453116a865f6f2ac52fa8ba198168a9f0a4e592fbb90f93a82516766da9",
+"T3T1_de_evolu-test_get_node.py::test_evolu_get_node_index_1": "f2fcbbd7ad83aff9adc0ee97fe98e7272d8bcfcc4a023798e2ab1c9895fda70f",
+"T3T1_de_evolu-test_get_node.py::test_evolu_get_node_index_change": "f2fcbbd7ad83aff9adc0ee97fe98e7272d8bcfcc4a023798e2ab1c9895fda70f",
"T3T1_de_evolu-test_get_node.py::test_evolu_get_node_invalid_proof": "5b317453116a865f6f2ac52fa8ba198168a9f0a4e592fbb90f93a82516766da9",
"T3T1_de_evolu-test_get_node.py::test_evolu_get_node_no_proof": "f2fcbbd7ad83aff9adc0ee97fe98e7272d8bcfcc4a023798e2ab1c9895fda70f",
"T3T1_de_evolu-test_get_node.py::test_evolu_get_node_none_proof": "f2fcbbd7ad83aff9adc0ee97fe98e7272d8bcfcc4a023798e2ab1c9895fda70f",
+"T3T1_de_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-0]": "5b317453116a865f6f2ac52fa8ba198168a9f0a4e592fbb90f93a82516766da9",
+"T3T1_de_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-42]": "5b317453116a865f6f2ac52fa8ba198168a9f0a4e592fbb90f93a82516766da9",
+"T3T1_de_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-None]": "5b317453116a865f6f2ac52fa8ba198168a9f0a4e592fbb90f93a82516766da9",
+"T3T1_de_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-0]": "5b317453116a865f6f2ac52fa8ba198168a9f0a4e592fbb90f93a82516766da9",
+"T3T1_de_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-42]": "5b317453116a865f6f2ac52fa8ba198168a9f0a4e592fbb90f93a82516766da9",
+"T3T1_de_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-None]": "5b317453116a865f6f2ac52fa8ba198168a9f0a4e592fbb90f93a82516766da9",
"T3T1_de_evolu-test_sign_registration.py::test_evolu_sign_request": "3ff7f28441ede54b92b110ae2a62e1449bec22c21875fcb9882f140c88fd9761",
"T3T1_de_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_long": "5b317453116a865f6f2ac52fa8ba198168a9f0a4e592fbb90f93a82516766da9",
"T3T1_de_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_short": "5b317453116a865f6f2ac52fa8ba198168a9f0a4e592fbb90f93a82516766da9",
@@ -23847,6 +24134,11 @@
"T3T1_de_evolu-test_sign_registration.py::test_evolu_sign_request_invalid_proof": "5b317453116a865f6f2ac52fa8ba198168a9f0a4e592fbb90f93a82516766da9",
"T3T1_de_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_large": "5b317453116a865f6f2ac52fa8ba198168a9f0a4e592fbb90f93a82516766da9",
"T3T1_de_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_small": "5b317453116a865f6f2ac52fa8ba198168a9f0a4e592fbb90f93a82516766da9",
+"T3T1_de_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[0]": "3ff7f28441ede54b92b110ae2a62e1449bec22c21875fcb9882f140c88fd9761",
+"T3T1_de_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[1]": "3ff7f28441ede54b92b110ae2a62e1449bec22c21875fcb9882f140c88fd9761",
+"T3T1_de_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[2]": "3ff7f28441ede54b92b110ae2a62e1449bec22c21875fcb9882f140c88fd9761",
+"T3T1_de_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[42]": "3ff7f28441ede54b92b110ae2a62e1449bec22c21875fcb9882f140c88fd9761",
+"T3T1_de_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[None]": "3ff7f28441ede54b92b110ae2a62e1449bec22c21875fcb9882f140c88fd9761",
"T3T1_de_misc-test_msg_cipherkeyvalue.py::test_decrypt": "a5f364be144da2e85f16482eb93d03b9f994d29d95edffd2fac939c61cc87563",
"T3T1_de_misc-test_msg_cipherkeyvalue.py::test_decrypt_badlen": "f2fcbbd7ad83aff9adc0ee97fe98e7272d8bcfcc4a023798e2ab1c9895fda70f",
"T3T1_de_misc-test_msg_cipherkeyvalue.py::test_encrypt": "7a38ab2100374df34a67182b5f665e098a844972ce989567d26aad6d343132ba",
@@ -25435,13 +25727,31 @@
"T3T1_en_ethereum-test_signtx.py::test_signtx_staking_eip1559[stake_main]": "574c66059d7c97996193c026460f903942095cad487587831eaa9d7a077baf3f",
"T3T1_en_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_hoodi]": "78bd9d94c2c4c49180f136e2e45b2f0e3fa6726f98a79e47c4eadfb07142b8e1",
"T3T1_en_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_main]": "621bce46eee320d506efabdae6284eeb25c354249eb5b32da2027ce3a373eea4",
+"T3T1_en_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation": "80fbdadeaecc89c370754d325cfcf3ad934ac66b76ce4591679b34784952e90e",
+"T3T1_en_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_index_increment": "4f96f44f026059ae9154174712304b10a0fc555ba83626d8f07ee0a48d132340",
+"T3T1_en_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_max_index": "cb8641952bec9e793e7d19f281a85a0ca1be2c3397ca5c0cf4ee7ad905429984",
+"T3T1_en_evolu-test_delegated_identity_key_rotation.py::test_explicit_index_zero_on_uninitialized_device": "6121f237803da54918de8521b8a3d1f4451b2ec6939ae3a7ef90593522f8c14f",
+"T3T1_en_evolu-test_delegated_identity_key_rotation.py::test_first_rotation_index_is_None": "6121f237803da54918de8521b8a3d1f4451b2ec6939ae3a7ef90593522f8c14f",
+"T3T1_en_evolu-test_delegated_identity_key_rotation.py::test_index_management_cannot_overwrite_existing_index": "d283ab0c33ae192784f56a739f663269899e493ff89f99066363142be817f922",
+"T3T1_en_evolu-test_delegated_identity_key_rotation.py::test_index_management_getter": "cb8641952bec9e793e7d19f281a85a0ca1be2c3397ca5c0cf4ee7ad905429984",
+"T3T1_en_evolu-test_delegated_identity_key_rotation.py::test_rotate_affects_index_management": "fdff75669c333da8ec01ee1310dbc7917f3b13422c1168b8d46ea519dedac98e",
+"T3T1_en_evolu-test_delegated_identity_key_rotation.py::test_rotation_index_wiped_on_device_wipe": "20be8ef9ff425ba2d21b064953c93fcb220dbb5fa80c6152f3697acac928b241",
"T3T1_en_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_is_constant": "6121f237803da54918de8521b8a3d1f4451b2ec6939ae3a7ef90593522f8c14f",
"T3T1_en_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_test_vector": "d283ab0c33ae192784f56a739f663269899e493ff89f99066363142be817f922",
"T3T1_en_evolu-test_get_node.py::test_evolu_get_node": "d283ab0c33ae192784f56a739f663269899e493ff89f99066363142be817f922",
-"T3T1_en_evolu-test_get_node.py::test_evolu_get_node_different_seed": "d283ab0c33ae192784f56a739f663269899e493ff89f99066363142be817f922",
+"T3T1_en_evolu-test_get_node.py::test_evolu_get_node_different_seed[TREZOR]": "f8140e74db7b726a6ab3f5c82904d540e2e61699324b797b884eb29bf8309c99",
+"T3T1_en_evolu-test_get_node.py::test_evolu_get_node_different_seed[]": "d283ab0c33ae192784f56a739f663269899e493ff89f99066363142be817f922",
+"T3T1_en_evolu-test_get_node.py::test_evolu_get_node_index_1": "cb8641952bec9e793e7d19f281a85a0ca1be2c3397ca5c0cf4ee7ad905429984",
+"T3T1_en_evolu-test_get_node.py::test_evolu_get_node_index_change": "cb8641952bec9e793e7d19f281a85a0ca1be2c3397ca5c0cf4ee7ad905429984",
"T3T1_en_evolu-test_get_node.py::test_evolu_get_node_invalid_proof": "d283ab0c33ae192784f56a739f663269899e493ff89f99066363142be817f922",
"T3T1_en_evolu-test_get_node.py::test_evolu_get_node_no_proof": "cb8641952bec9e793e7d19f281a85a0ca1be2c3397ca5c0cf4ee7ad905429984",
"T3T1_en_evolu-test_get_node.py::test_evolu_get_node_none_proof": "cb8641952bec9e793e7d19f281a85a0ca1be2c3397ca5c0cf4ee7ad905429984",
+"T3T1_en_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-0]": "d283ab0c33ae192784f56a739f663269899e493ff89f99066363142be817f922",
+"T3T1_en_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-42]": "d283ab0c33ae192784f56a739f663269899e493ff89f99066363142be817f922",
+"T3T1_en_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-None]": "d283ab0c33ae192784f56a739f663269899e493ff89f99066363142be817f922",
+"T3T1_en_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-0]": "d283ab0c33ae192784f56a739f663269899e493ff89f99066363142be817f922",
+"T3T1_en_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-42]": "d283ab0c33ae192784f56a739f663269899e493ff89f99066363142be817f922",
+"T3T1_en_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-None]": "d283ab0c33ae192784f56a739f663269899e493ff89f99066363142be817f922",
"T3T1_en_evolu-test_sign_registration.py::test_evolu_sign_request": "6121f237803da54918de8521b8a3d1f4451b2ec6939ae3a7ef90593522f8c14f",
"T3T1_en_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_long": "d283ab0c33ae192784f56a739f663269899e493ff89f99066363142be817f922",
"T3T1_en_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_short": "d283ab0c33ae192784f56a739f663269899e493ff89f99066363142be817f922",
@@ -25449,6 +25759,11 @@
"T3T1_en_evolu-test_sign_registration.py::test_evolu_sign_request_invalid_proof": "d283ab0c33ae192784f56a739f663269899e493ff89f99066363142be817f922",
"T3T1_en_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_large": "d283ab0c33ae192784f56a739f663269899e493ff89f99066363142be817f922",
"T3T1_en_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_small": "d283ab0c33ae192784f56a739f663269899e493ff89f99066363142be817f922",
+"T3T1_en_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[0]": "6121f237803da54918de8521b8a3d1f4451b2ec6939ae3a7ef90593522f8c14f",
+"T3T1_en_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[1]": "6121f237803da54918de8521b8a3d1f4451b2ec6939ae3a7ef90593522f8c14f",
+"T3T1_en_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[2]": "6121f237803da54918de8521b8a3d1f4451b2ec6939ae3a7ef90593522f8c14f",
+"T3T1_en_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[42]": "6121f237803da54918de8521b8a3d1f4451b2ec6939ae3a7ef90593522f8c14f",
+"T3T1_en_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[None]": "6121f237803da54918de8521b8a3d1f4451b2ec6939ae3a7ef90593522f8c14f",
"T3T1_en_misc-test_msg_cipherkeyvalue.py::test_decrypt": "20adb27bb11ffea69f351b2b01b84972c30a44b4b527844edf8b1f9dde4e667d",
"T3T1_en_misc-test_msg_cipherkeyvalue.py::test_decrypt_badlen": "cb8641952bec9e793e7d19f281a85a0ca1be2c3397ca5c0cf4ee7ad905429984",
"T3T1_en_misc-test_msg_cipherkeyvalue.py::test_encrypt": "3b19246cb825321b5ab7aadf6806c158ecf07b66fc709fb69ab1cb2e53c9b671",
@@ -27037,13 +27352,31 @@
"T3T1_es_ethereum-test_signtx.py::test_signtx_staking_eip1559[stake_main]": "5a51f4032a63cb4f2a4a7aeecaf441fb0acdb7b20bb6bdab239abf4402870ab8",
"T3T1_es_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_hoodi]": "4dc53e19a91f752ef021e7b627361735571bd7dc8e818625031c2097d97c2f89",
"T3T1_es_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_main]": "bec96eb54de76ed6f1c10bcfe57efb83447d7509041564ca605b430a1f70eefb",
+"T3T1_es_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation": "1933d146abe44536133d17d7b9a23ab60846f768035decae100f572c4528b974",
+"T3T1_es_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_index_increment": "0f7418b05539e830163a321f1cdd978da6a036ee0395028eba10275decf43ba1",
+"T3T1_es_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_max_index": "c568b82943d9f63ad6b29b7dee6f5ed9dca78fc9610d4fa7f12bb8a061a6882a",
+"T3T1_es_evolu-test_delegated_identity_key_rotation.py::test_explicit_index_zero_on_uninitialized_device": "2815acf23ccbbebb2ba013299275e90df2eb5134312196824c7576f02808901c",
+"T3T1_es_evolu-test_delegated_identity_key_rotation.py::test_first_rotation_index_is_None": "2815acf23ccbbebb2ba013299275e90df2eb5134312196824c7576f02808901c",
+"T3T1_es_evolu-test_delegated_identity_key_rotation.py::test_index_management_cannot_overwrite_existing_index": "d0e5951e2ef75d653d24f5bfd9e2def183e52a0fb5b4adccd6c6d5d4b4ec2618",
+"T3T1_es_evolu-test_delegated_identity_key_rotation.py::test_index_management_getter": "c568b82943d9f63ad6b29b7dee6f5ed9dca78fc9610d4fa7f12bb8a061a6882a",
+"T3T1_es_evolu-test_delegated_identity_key_rotation.py::test_rotate_affects_index_management": "522ac92c7e0ccc3418c37c363fc584891e64183c8ebd3bb517c85ccae8cb6345",
+"T3T1_es_evolu-test_delegated_identity_key_rotation.py::test_rotation_index_wiped_on_device_wipe": "07f7f2172a0b54fd66d7adc7e054beb249fd20912567a70e79e13ef98f9992fd",
"T3T1_es_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_is_constant": "2815acf23ccbbebb2ba013299275e90df2eb5134312196824c7576f02808901c",
"T3T1_es_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_test_vector": "d0e5951e2ef75d653d24f5bfd9e2def183e52a0fb5b4adccd6c6d5d4b4ec2618",
"T3T1_es_evolu-test_get_node.py::test_evolu_get_node": "d0e5951e2ef75d653d24f5bfd9e2def183e52a0fb5b4adccd6c6d5d4b4ec2618",
-"T3T1_es_evolu-test_get_node.py::test_evolu_get_node_different_seed": "d0e5951e2ef75d653d24f5bfd9e2def183e52a0fb5b4adccd6c6d5d4b4ec2618",
+"T3T1_es_evolu-test_get_node.py::test_evolu_get_node_different_seed[TREZOR]": "97829584237dd0217345e117e9c86443bfc0afdc8a4020a6c992129776c92c40",
+"T3T1_es_evolu-test_get_node.py::test_evolu_get_node_different_seed[]": "d0e5951e2ef75d653d24f5bfd9e2def183e52a0fb5b4adccd6c6d5d4b4ec2618",
+"T3T1_es_evolu-test_get_node.py::test_evolu_get_node_index_1": "c568b82943d9f63ad6b29b7dee6f5ed9dca78fc9610d4fa7f12bb8a061a6882a",
+"T3T1_es_evolu-test_get_node.py::test_evolu_get_node_index_change": "c568b82943d9f63ad6b29b7dee6f5ed9dca78fc9610d4fa7f12bb8a061a6882a",
"T3T1_es_evolu-test_get_node.py::test_evolu_get_node_invalid_proof": "d0e5951e2ef75d653d24f5bfd9e2def183e52a0fb5b4adccd6c6d5d4b4ec2618",
"T3T1_es_evolu-test_get_node.py::test_evolu_get_node_no_proof": "c568b82943d9f63ad6b29b7dee6f5ed9dca78fc9610d4fa7f12bb8a061a6882a",
"T3T1_es_evolu-test_get_node.py::test_evolu_get_node_none_proof": "c568b82943d9f63ad6b29b7dee6f5ed9dca78fc9610d4fa7f12bb8a061a6882a",
+"T3T1_es_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-0]": "d0e5951e2ef75d653d24f5bfd9e2def183e52a0fb5b4adccd6c6d5d4b4ec2618",
+"T3T1_es_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-42]": "d0e5951e2ef75d653d24f5bfd9e2def183e52a0fb5b4adccd6c6d5d4b4ec2618",
+"T3T1_es_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-None]": "d0e5951e2ef75d653d24f5bfd9e2def183e52a0fb5b4adccd6c6d5d4b4ec2618",
+"T3T1_es_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-0]": "d0e5951e2ef75d653d24f5bfd9e2def183e52a0fb5b4adccd6c6d5d4b4ec2618",
+"T3T1_es_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-42]": "d0e5951e2ef75d653d24f5bfd9e2def183e52a0fb5b4adccd6c6d5d4b4ec2618",
+"T3T1_es_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-None]": "d0e5951e2ef75d653d24f5bfd9e2def183e52a0fb5b4adccd6c6d5d4b4ec2618",
"T3T1_es_evolu-test_sign_registration.py::test_evolu_sign_request": "2815acf23ccbbebb2ba013299275e90df2eb5134312196824c7576f02808901c",
"T3T1_es_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_long": "d0e5951e2ef75d653d24f5bfd9e2def183e52a0fb5b4adccd6c6d5d4b4ec2618",
"T3T1_es_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_short": "d0e5951e2ef75d653d24f5bfd9e2def183e52a0fb5b4adccd6c6d5d4b4ec2618",
@@ -27051,6 +27384,11 @@
"T3T1_es_evolu-test_sign_registration.py::test_evolu_sign_request_invalid_proof": "d0e5951e2ef75d653d24f5bfd9e2def183e52a0fb5b4adccd6c6d5d4b4ec2618",
"T3T1_es_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_large": "d0e5951e2ef75d653d24f5bfd9e2def183e52a0fb5b4adccd6c6d5d4b4ec2618",
"T3T1_es_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_small": "d0e5951e2ef75d653d24f5bfd9e2def183e52a0fb5b4adccd6c6d5d4b4ec2618",
+"T3T1_es_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[0]": "2815acf23ccbbebb2ba013299275e90df2eb5134312196824c7576f02808901c",
+"T3T1_es_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[1]": "2815acf23ccbbebb2ba013299275e90df2eb5134312196824c7576f02808901c",
+"T3T1_es_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[2]": "2815acf23ccbbebb2ba013299275e90df2eb5134312196824c7576f02808901c",
+"T3T1_es_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[42]": "2815acf23ccbbebb2ba013299275e90df2eb5134312196824c7576f02808901c",
+"T3T1_es_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[None]": "2815acf23ccbbebb2ba013299275e90df2eb5134312196824c7576f02808901c",
"T3T1_es_misc-test_msg_cipherkeyvalue.py::test_decrypt": "5ac1560df7c7bb71ed28c4c5e4f254b8c497b2bf282720a4cafc8c0bc5f9ee4c",
"T3T1_es_misc-test_msg_cipherkeyvalue.py::test_decrypt_badlen": "c568b82943d9f63ad6b29b7dee6f5ed9dca78fc9610d4fa7f12bb8a061a6882a",
"T3T1_es_misc-test_msg_cipherkeyvalue.py::test_encrypt": "3e6e4b13dfc4f4ee6529c96e33d7b761b011d2af79f100d9a91fef380c8a916d",
@@ -28639,13 +28977,31 @@
"T3T1_fr_ethereum-test_signtx.py::test_signtx_staking_eip1559[stake_main]": "931ba7a813caae3edd7f98e10de29bde2958ca245fedff8b905d99fdb7e8ad03",
"T3T1_fr_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_hoodi]": "fa4e4e99841b6b36c78f6db074fda320e2c991d46488509d51db99f53da78abe",
"T3T1_fr_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_main]": "a03d0d0c4945105ee57062fa3942c0dec57f23df27410253cadd7a8bdc23f8c8",
+"T3T1_fr_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation": "7fa70b64196db7596e832b0aa7d79b73461f94edbdb0a2a1f94b435258d24079",
+"T3T1_fr_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_index_increment": "da52ee9a5513926b76af2c7415996432b2e8670343ba3fcaef4141e28d79a4bc",
+"T3T1_fr_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_max_index": "fdf4909aff89183fa79899fde974115e687a71e0cf09dea210e8aa60ba54c906",
+"T3T1_fr_evolu-test_delegated_identity_key_rotation.py::test_explicit_index_zero_on_uninitialized_device": "876c52fce0b21ce0efa5113977e7b8fdc1feb0374aebc20083891b4318e69e45",
+"T3T1_fr_evolu-test_delegated_identity_key_rotation.py::test_first_rotation_index_is_None": "876c52fce0b21ce0efa5113977e7b8fdc1feb0374aebc20083891b4318e69e45",
+"T3T1_fr_evolu-test_delegated_identity_key_rotation.py::test_index_management_cannot_overwrite_existing_index": "ed7512c94925df7adbe1b21cb2b119285503001c7a3d8bae3c7e43052889e1e6",
+"T3T1_fr_evolu-test_delegated_identity_key_rotation.py::test_index_management_getter": "fdf4909aff89183fa79899fde974115e687a71e0cf09dea210e8aa60ba54c906",
+"T3T1_fr_evolu-test_delegated_identity_key_rotation.py::test_rotate_affects_index_management": "b7f24721226476451154338e0b92afdc7d8711b9c9bd3b42149f41ef60b317c6",
+"T3T1_fr_evolu-test_delegated_identity_key_rotation.py::test_rotation_index_wiped_on_device_wipe": "2fbc3ab12820af7a0deb77fc4b9b8cdba8d8841f5525e2810621e673ded73213",
"T3T1_fr_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_is_constant": "876c52fce0b21ce0efa5113977e7b8fdc1feb0374aebc20083891b4318e69e45",
"T3T1_fr_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_test_vector": "ed7512c94925df7adbe1b21cb2b119285503001c7a3d8bae3c7e43052889e1e6",
"T3T1_fr_evolu-test_get_node.py::test_evolu_get_node": "ed7512c94925df7adbe1b21cb2b119285503001c7a3d8bae3c7e43052889e1e6",
-"T3T1_fr_evolu-test_get_node.py::test_evolu_get_node_different_seed": "ed7512c94925df7adbe1b21cb2b119285503001c7a3d8bae3c7e43052889e1e6",
+"T3T1_fr_evolu-test_get_node.py::test_evolu_get_node_different_seed[TREZOR]": "c1e7567824a67d34d3c86ed7e486230a949000123d70f0cda146413f0a34c0a4",
+"T3T1_fr_evolu-test_get_node.py::test_evolu_get_node_different_seed[]": "ed7512c94925df7adbe1b21cb2b119285503001c7a3d8bae3c7e43052889e1e6",
+"T3T1_fr_evolu-test_get_node.py::test_evolu_get_node_index_1": "fdf4909aff89183fa79899fde974115e687a71e0cf09dea210e8aa60ba54c906",
+"T3T1_fr_evolu-test_get_node.py::test_evolu_get_node_index_change": "fdf4909aff89183fa79899fde974115e687a71e0cf09dea210e8aa60ba54c906",
"T3T1_fr_evolu-test_get_node.py::test_evolu_get_node_invalid_proof": "ed7512c94925df7adbe1b21cb2b119285503001c7a3d8bae3c7e43052889e1e6",
"T3T1_fr_evolu-test_get_node.py::test_evolu_get_node_no_proof": "fdf4909aff89183fa79899fde974115e687a71e0cf09dea210e8aa60ba54c906",
"T3T1_fr_evolu-test_get_node.py::test_evolu_get_node_none_proof": "fdf4909aff89183fa79899fde974115e687a71e0cf09dea210e8aa60ba54c906",
+"T3T1_fr_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-0]": "ed7512c94925df7adbe1b21cb2b119285503001c7a3d8bae3c7e43052889e1e6",
+"T3T1_fr_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-42]": "ed7512c94925df7adbe1b21cb2b119285503001c7a3d8bae3c7e43052889e1e6",
+"T3T1_fr_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-None]": "ed7512c94925df7adbe1b21cb2b119285503001c7a3d8bae3c7e43052889e1e6",
+"T3T1_fr_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-0]": "ed7512c94925df7adbe1b21cb2b119285503001c7a3d8bae3c7e43052889e1e6",
+"T3T1_fr_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-42]": "ed7512c94925df7adbe1b21cb2b119285503001c7a3d8bae3c7e43052889e1e6",
+"T3T1_fr_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-None]": "ed7512c94925df7adbe1b21cb2b119285503001c7a3d8bae3c7e43052889e1e6",
"T3T1_fr_evolu-test_sign_registration.py::test_evolu_sign_request": "876c52fce0b21ce0efa5113977e7b8fdc1feb0374aebc20083891b4318e69e45",
"T3T1_fr_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_long": "ed7512c94925df7adbe1b21cb2b119285503001c7a3d8bae3c7e43052889e1e6",
"T3T1_fr_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_short": "ed7512c94925df7adbe1b21cb2b119285503001c7a3d8bae3c7e43052889e1e6",
@@ -28653,6 +29009,11 @@
"T3T1_fr_evolu-test_sign_registration.py::test_evolu_sign_request_invalid_proof": "ed7512c94925df7adbe1b21cb2b119285503001c7a3d8bae3c7e43052889e1e6",
"T3T1_fr_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_large": "ed7512c94925df7adbe1b21cb2b119285503001c7a3d8bae3c7e43052889e1e6",
"T3T1_fr_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_small": "ed7512c94925df7adbe1b21cb2b119285503001c7a3d8bae3c7e43052889e1e6",
+"T3T1_fr_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[0]": "876c52fce0b21ce0efa5113977e7b8fdc1feb0374aebc20083891b4318e69e45",
+"T3T1_fr_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[1]": "876c52fce0b21ce0efa5113977e7b8fdc1feb0374aebc20083891b4318e69e45",
+"T3T1_fr_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[2]": "876c52fce0b21ce0efa5113977e7b8fdc1feb0374aebc20083891b4318e69e45",
+"T3T1_fr_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[42]": "876c52fce0b21ce0efa5113977e7b8fdc1feb0374aebc20083891b4318e69e45",
+"T3T1_fr_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[None]": "876c52fce0b21ce0efa5113977e7b8fdc1feb0374aebc20083891b4318e69e45",
"T3T1_fr_misc-test_msg_cipherkeyvalue.py::test_decrypt": "a22b8361abe91e71b8ab7d6796b900469370906b4cd652d9a72ddb5ff90dc129",
"T3T1_fr_misc-test_msg_cipherkeyvalue.py::test_decrypt_badlen": "fdf4909aff89183fa79899fde974115e687a71e0cf09dea210e8aa60ba54c906",
"T3T1_fr_misc-test_msg_cipherkeyvalue.py::test_encrypt": "81d9665cf47614f9a4f81be69ce56044a9f9265e2f40411b80e7808f8a09d8bf",
@@ -30241,13 +30602,31 @@
"T3T1_pt_ethereum-test_signtx.py::test_signtx_staking_eip1559[stake_main]": "ca36c038104761911f4a76ddbfc253729cfb8295c438735ad00b2e6ac8cc851a",
"T3T1_pt_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_hoodi]": "1cfbd33e6d7c46fb31c0df25270eb54a14ff9db882776ba45a8184c2ab695667",
"T3T1_pt_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_main]": "2348d5141d59aee2ab20b17f8884c47438089f21372cd07230fe778a9b6e0bf2",
+"T3T1_pt_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation": "a51529f827c0e159c17ce4c8662f952e98a8d4d8989cd478e6adfed1cb859bf0",
+"T3T1_pt_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_index_increment": "ae0ad7838ee33598df884104543481122508066d9e085c115dcd7a31b6d6e541",
+"T3T1_pt_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_max_index": "c15216b8aa033bd81f0a8fb6415c6728320b0c30fe3150eeb8a1749ae0a1a83c",
+"T3T1_pt_evolu-test_delegated_identity_key_rotation.py::test_explicit_index_zero_on_uninitialized_device": "24f806e6119854a3c316bbb6a7647b4e8b42fecf29db87363f9460200044db9a",
+"T3T1_pt_evolu-test_delegated_identity_key_rotation.py::test_first_rotation_index_is_None": "24f806e6119854a3c316bbb6a7647b4e8b42fecf29db87363f9460200044db9a",
+"T3T1_pt_evolu-test_delegated_identity_key_rotation.py::test_index_management_cannot_overwrite_existing_index": "f279cb13df78ec52e9243bb77d6a459620c3703744eb77989d7a11ce59da8936",
+"T3T1_pt_evolu-test_delegated_identity_key_rotation.py::test_index_management_getter": "c15216b8aa033bd81f0a8fb6415c6728320b0c30fe3150eeb8a1749ae0a1a83c",
+"T3T1_pt_evolu-test_delegated_identity_key_rotation.py::test_rotate_affects_index_management": "cfc43fcbe14b31e83a3ed2b27440be3ba6c42402834bff777c6c38bb53730309",
+"T3T1_pt_evolu-test_delegated_identity_key_rotation.py::test_rotation_index_wiped_on_device_wipe": "6de258742d7b2ee67ed8b9a988614c367504b754706f6a9915339425b0d21ab7",
"T3T1_pt_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_is_constant": "24f806e6119854a3c316bbb6a7647b4e8b42fecf29db87363f9460200044db9a",
"T3T1_pt_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_test_vector": "f279cb13df78ec52e9243bb77d6a459620c3703744eb77989d7a11ce59da8936",
"T3T1_pt_evolu-test_get_node.py::test_evolu_get_node": "f279cb13df78ec52e9243bb77d6a459620c3703744eb77989d7a11ce59da8936",
-"T3T1_pt_evolu-test_get_node.py::test_evolu_get_node_different_seed": "f279cb13df78ec52e9243bb77d6a459620c3703744eb77989d7a11ce59da8936",
+"T3T1_pt_evolu-test_get_node.py::test_evolu_get_node_different_seed[TREZOR]": "7d841ea7a4e693bddff3a1c128ab63e91323fd096e99a6bdda2877a05c6904d9",
+"T3T1_pt_evolu-test_get_node.py::test_evolu_get_node_different_seed[]": "f279cb13df78ec52e9243bb77d6a459620c3703744eb77989d7a11ce59da8936",
+"T3T1_pt_evolu-test_get_node.py::test_evolu_get_node_index_1": "c15216b8aa033bd81f0a8fb6415c6728320b0c30fe3150eeb8a1749ae0a1a83c",
+"T3T1_pt_evolu-test_get_node.py::test_evolu_get_node_index_change": "c15216b8aa033bd81f0a8fb6415c6728320b0c30fe3150eeb8a1749ae0a1a83c",
"T3T1_pt_evolu-test_get_node.py::test_evolu_get_node_invalid_proof": "f279cb13df78ec52e9243bb77d6a459620c3703744eb77989d7a11ce59da8936",
"T3T1_pt_evolu-test_get_node.py::test_evolu_get_node_no_proof": "c15216b8aa033bd81f0a8fb6415c6728320b0c30fe3150eeb8a1749ae0a1a83c",
"T3T1_pt_evolu-test_get_node.py::test_evolu_get_node_none_proof": "c15216b8aa033bd81f0a8fb6415c6728320b0c30fe3150eeb8a1749ae0a1a83c",
+"T3T1_pt_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-0]": "f279cb13df78ec52e9243bb77d6a459620c3703744eb77989d7a11ce59da8936",
+"T3T1_pt_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-42]": "f279cb13df78ec52e9243bb77d6a459620c3703744eb77989d7a11ce59da8936",
+"T3T1_pt_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-None]": "f279cb13df78ec52e9243bb77d6a459620c3703744eb77989d7a11ce59da8936",
+"T3T1_pt_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-0]": "f279cb13df78ec52e9243bb77d6a459620c3703744eb77989d7a11ce59da8936",
+"T3T1_pt_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-42]": "f279cb13df78ec52e9243bb77d6a459620c3703744eb77989d7a11ce59da8936",
+"T3T1_pt_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-None]": "f279cb13df78ec52e9243bb77d6a459620c3703744eb77989d7a11ce59da8936",
"T3T1_pt_evolu-test_sign_registration.py::test_evolu_sign_request": "24f806e6119854a3c316bbb6a7647b4e8b42fecf29db87363f9460200044db9a",
"T3T1_pt_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_long": "f279cb13df78ec52e9243bb77d6a459620c3703744eb77989d7a11ce59da8936",
"T3T1_pt_evolu-test_sign_registration.py::test_evolu_sign_request_challenge_too_short": "f279cb13df78ec52e9243bb77d6a459620c3703744eb77989d7a11ce59da8936",
@@ -30255,6 +30634,11 @@
"T3T1_pt_evolu-test_sign_registration.py::test_evolu_sign_request_invalid_proof": "f279cb13df78ec52e9243bb77d6a459620c3703744eb77989d7a11ce59da8936",
"T3T1_pt_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_large": "f279cb13df78ec52e9243bb77d6a459620c3703744eb77989d7a11ce59da8936",
"T3T1_pt_evolu-test_sign_registration.py::test_evolu_sign_request_size_too_small": "f279cb13df78ec52e9243bb77d6a459620c3703744eb77989d7a11ce59da8936",
+"T3T1_pt_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[0]": "24f806e6119854a3c316bbb6a7647b4e8b42fecf29db87363f9460200044db9a",
+"T3T1_pt_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[1]": "24f806e6119854a3c316bbb6a7647b4e8b42fecf29db87363f9460200044db9a",
+"T3T1_pt_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[2]": "24f806e6119854a3c316bbb6a7647b4e8b42fecf29db87363f9460200044db9a",
+"T3T1_pt_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[42]": "24f806e6119854a3c316bbb6a7647b4e8b42fecf29db87363f9460200044db9a",
+"T3T1_pt_evolu-test_sign_registration.py::test_evolu_sign_request_with_different_rotation_indices[None]": "24f806e6119854a3c316bbb6a7647b4e8b42fecf29db87363f9460200044db9a",
"T3T1_pt_misc-test_msg_cipherkeyvalue.py::test_decrypt": "088162fb4032b55559e14d09a58a6285504f0285f5d31bf6af1ee9f4599fcdba",
"T3T1_pt_misc-test_msg_cipherkeyvalue.py::test_decrypt_badlen": "c15216b8aa033bd81f0a8fb6415c6728320b0c30fe3150eeb8a1749ae0a1a83c",
"T3T1_pt_misc-test_msg_cipherkeyvalue.py::test_encrypt": "bd0a2145479ae51f06b9095249ceea2f85bebab73a452938fd852a6471c0f87d",
@@ -32489,13 +32873,31 @@
"T3W1_cs_ethereum-test_signtx.py::test_signtx_staking_eip1559[stake_main]": "9bcb53023c00d5eafdb0c7bb986453bf05ab7cf9810df6937698ae0b744d480c",
"T3W1_cs_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_hoodi]": "5d80ed0f848fd7ea631584211f69d5d07859e519c447f52223888bc29ea4d938",
"T3W1_cs_ethereum-test_signtx.py::test_signtx_staking_eip1559[unstake_main]": "c646dcf21f2529b9ed453fdbe16f25d8a3f8b7b2b0722302a3f6f85bd7117777",
+"T3W1_cs_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation": "7de5c6b395110da9c2f801a5819811e8416a2f7c313fb806485b7b316a55d46d",
+"T3W1_cs_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_index_increment": "5d7c066b037da8986f77a2f18ec36fbb02a3ace9b555b306c39fd03e39132436",
+"T3W1_cs_evolu-test_delegated_identity_key_rotation.py::test_delegated_identity_key_rotation_max_index": "cda715bca8af82c3d4193edcf9f89c0eb8080f8e89da3015e048381df7dbba51",
+"T3W1_cs_evolu-test_delegated_identity_key_rotation.py::test_explicit_index_zero_on_uninitialized_device": "d0b9c2b9bb25619bc419157aef424511bd81fda688916bf692cbfe44975ecf07",
+"T3W1_cs_evolu-test_delegated_identity_key_rotation.py::test_first_rotation_index_is_None": "d0b9c2b9bb25619bc419157aef424511bd81fda688916bf692cbfe44975ecf07",
+"T3W1_cs_evolu-test_delegated_identity_key_rotation.py::test_index_management_cannot_overwrite_existing_index": "767e31f1b886dee1dad9c9271039e7382e05f03b59d87b7e6149ba96ffb8b4af",
+"T3W1_cs_evolu-test_delegated_identity_key_rotation.py::test_index_management_getter": "cda715bca8af82c3d4193edcf9f89c0eb8080f8e89da3015e048381df7dbba51",
+"T3W1_cs_evolu-test_delegated_identity_key_rotation.py::test_rotate_affects_index_management": "56afa3242442992a4692ae0a2677d49d7f176a4736105c37e6cd70e365cf3e33",
+"T3W1_cs_evolu-test_delegated_identity_key_rotation.py::test_rotation_index_wiped_on_device_wipe": "3db9dcf88e310b201c921c9dac27afc9bfe424debc07712d1e3fc3d783bdb4d7",
"T3W1_cs_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_is_constant": "d0b9c2b9bb25619bc419157aef424511bd81fda688916bf692cbfe44975ecf07",
"T3W1_cs_evolu-test_get_delegated_identity_key.py::test_evolu_get_delegated_identity_test_vector": "767e31f1b886dee1dad9c9271039e7382e05f03b59d87b7e6149ba96ffb8b4af",
"T3W1_cs_evolu-test_get_node.py::test_evolu_get_node": "767e31f1b886dee1dad9c9271039e7382e05f03b59d87b7e6149ba96ffb8b4af",
-"T3W1_cs_evolu-test_get_node.py::test_evolu_get_node_different_seed": "767e31f1b886dee1dad9c9271039e7382e05f03b59d87b7e6149ba96ffb8b4af",
+"T3W1_cs_evolu-test_get_node.py::test_evolu_get_node_different_seed[TREZOR]": "95c5dde84200c0aaba7006ea66f6fca05b749f96d7bd2d9772217631535ff4ed",
+"T3W1_cs_evolu-test_get_node.py::test_evolu_get_node_different_seed[]": "767e31f1b886dee1dad9c9271039e7382e05f03b59d87b7e6149ba96ffb8b4af",
+"T3W1_cs_evolu-test_get_node.py::test_evolu_get_node_index_1": "cda715bca8af82c3d4193edcf9f89c0eb8080f8e89da3015e048381df7dbba51",
+"T3W1_cs_evolu-test_get_node.py::test_evolu_get_node_index_change": "cda715bca8af82c3d4193edcf9f89c0eb8080f8e89da3015e048381df7dbba51",
"T3W1_cs_evolu-test_get_node.py::test_evolu_get_node_invalid_proof": "767e31f1b886dee1dad9c9271039e7382e05f03b59d87b7e6149ba96ffb8b4af",
"T3W1_cs_evolu-test_get_node.py::test_evolu_get_node_no_proof": "cda715bca8af82c3d4193edcf9f89c0eb8080f8e89da3015e048381df7dbba51",
"T3W1_cs_evolu-test_get_node.py::test_evolu_get_node_none_proof": "cda715bca8af82c3d4193edcf9f89c0eb8080f8e89da3015e048381df7dbba51",
+"T3W1_cs_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-0]": "767e31f1b886dee1dad9c9271039e7382e05f03b59d87b7e6149ba96ffb8b4af",
+"T3W1_cs_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-42]": "767e31f1b886dee1dad9c9271039e7382e05f03b59d87b7e6149ba96ffb8b4af",
+"T3W1_cs_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[0-None]": "767e31f1b886dee1dad9c9271039e7382e05f03b59d87b7e6149ba96ffb8b4af",
+"T3W1_cs_evolu-test_get_node.py::test_evolu_get_node_with_different_rotation_indices[1-0Why this scored 37/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.