diff --git a/src/common/ui/display_nbgl.c b/src/common/ui/display_nbgl.c index 1aaf38b..fd4d758 100644 --- a/src/common/ui/display_nbgl.c +++ b/src/common/ui/display_nbgl.c @@ -380,21 +380,90 @@ void startConfigureDelegationDisplay(void) { } void uiSignUpdateCredentialThresholdDisplay(volatile unsigned int *flags) { - return; + // Create tag-value pairs for the content + uint8_t pairIndex = 0; + + // Add threshold information + pairs[pairIndex].item = "Threshold"; + pairs[pairIndex].value = (char *)global.signCredentialDeploymentContext.threshold; + pairIndex++; + + // Create the page content + nbgl_contentTagValueList_t content; + content.nbPairs = pairIndex; + content.pairs = pairs; + content.smallCaseForValue = false; + content.nbMaxLinesForValue = 0; + content.startIndex = 0; + + // Setup the review screen - this is the final step so use nbgl_useCaseReview + nbgl_useCaseReview(TYPE_TRANSACTION, + &content, + &C_app_concordium_64px, + "Review Transaction", + NULL, // No subtitle + "Sign transaction", + review_choice_sign); + *flags |= IO_ASYNCH_REPLY; - // TODO: Implement this } void uiSignUpdateCredentialInitialDisplay(volatile unsigned int *flags) { - return; + // Create tag-value pairs for the content + uint8_t pairIndex = 0; + + // Add sender address + pairs[pairIndex].item = "Sender"; + pairs[pairIndex].value = (char *)global_account_sender.sender; + pairIndex++; + + // Create the page content + nbgl_contentTagValueList_t content; + content.nbPairs = pairIndex; + content.pairs = pairs; + content.smallCaseForValue = false; + content.nbMaxLinesForValue = 0; + content.startIndex = 0; + + // Setup the review screen + nbgl_useCaseReviewLight(TYPE_OPERATION, + &content, + &C_app_concordium_64px, + "Review", + "details", + "Continue with transaction", + sendSuccessNoIdleCallback); + *flags |= IO_ASYNCH_REPLY; - // TODO: Implement this } void uiSignUpdateCredentialIdDisplay(volatile unsigned int *flags) { - return; + // Create tag-value pairs for the content + uint8_t pairIndex = 0; + + // Add credential ID information + pairs[pairIndex].item = "Credential ID"; + pairs[pairIndex].value = (char *)global.signCredentialDeploymentContext.credentialId; + pairIndex++; + + // Create the page content + nbgl_contentTagValueList_t content; + content.nbPairs = pairIndex; + content.pairs = pairs; + content.smallCaseForValue = false; + content.nbMaxLinesForValue = 0; + content.startIndex = 0; + + // Setup the review screen + nbgl_useCaseReviewLight(TYPE_OPERATION, + &content, + &C_app_concordium_64px, + "Review", + "details", + "Continue with transaction", + sendSuccessNoIdleCallback); + *flags |= IO_ASYNCH_REPLY; - // TODO: Implement this } void uiSignCredentialDeploymentVerificationKeyDisplay(volatile unsigned int *flags) { diff --git a/tests/application_client/boilerplate_command_sender.py b/tests/application_client/boilerplate_command_sender.py index e30c70f..b765a04 100644 --- a/tests/application_client/boilerplate_command_sender.py +++ b/tests/application_client/boilerplate_command_sender.py @@ -712,6 +712,157 @@ def credential_deployment_part_3( print("km--------sent new or existing", response) yield response + @contextmanager + def credential_update_part_1( + self, + data: bytes, + ) -> Generator[None, None, None]: + with self.backend.exchange_async( + cla=CLA, + ins=InsType.SIGN_UPDATE_CREDENTIAL, + p1=P1.P1_NONE, + p2=P2.P2_NONE, + data=data, + ) as response: + yield response + + @contextmanager + def sign_update_credential_part_2( + self, + key_index: bytes, + number_of_keys: int, + key: bytes, + ) -> Generator[None, None, None]: + # Send all keys + with self.backend.exchange_async( + cla=CLA, + ins=InsType.SIGN_UPDATE_CREDENTIAL, + p1=P1.P1_NONE, + p2=P2.P2_CREDENTIAL_CREDENTIAL_INDEX, + data=key_index, + ): + pass + with self.backend.exchange_async( + cla=CLA, + ins=InsType.SIGN_UPDATE_CREDENTIAL, + p1=P1.P1_VERIFICATION_KEY_LENGTH, + p2=P2.P2_CREDENTIAL_CREDENTIAL, + data=bytes.fromhex(f"{number_of_keys:02x}"), + ): + pass + with self.backend.exchange_async( + cla=CLA, + ins=InsType.SIGN_UPDATE_CREDENTIAL, + p1=P1.P1_VERIFICATION_KEY, + p2=P2.P2_CREDENTIAL_CREDENTIAL, + data=key, + ) as response: + yield response + + @contextmanager + def sign_update_credential_part_3( + self, + signature_threshold: bytes, + ar_identity: bytes, + credential_dates: bytes, + attribute_tag: bytes, + attribute_value: bytes, + proof_length: bytes, + proofs: bytes, + credential_id_list: List[bytes], + ) -> Generator[None, None, None]: + with self.backend.exchange_async( + cla=CLA, + ins=InsType.SIGN_UPDATE_CREDENTIAL, + p1=P1.P1_SIGNATURE_THRESHOLD, + p2=P2.P2_CREDENTIAL_CREDENTIAL, + data=signature_threshold, + ): + pass + + with self.backend.exchange_async( + cla=CLA, + ins=InsType.SIGN_UPDATE_CREDENTIAL, + p1=P1.P1_AR_IDENTITY, + p2=P2.P2_CREDENTIAL_CREDENTIAL, + data=ar_identity, + ): + pass + with self.backend.exchange_async( + cla=CLA, + ins=InsType.SIGN_UPDATE_CREDENTIAL, + p1=P1.P1_CREDENTIAL_DATES, + p2=P2.P2_CREDENTIAL_CREDENTIAL, + data=credential_dates, + ): + pass + with self.backend.exchange_async( + cla=CLA, + ins=InsType.SIGN_UPDATE_CREDENTIAL, + p1=P1.P1_ATTRIBUTE_TAG, + p2=P2.P2_CREDENTIAL_CREDENTIAL, + data=attribute_tag, + ): + pass + with self.backend.exchange_async( + cla=CLA, + ins=InsType.SIGN_UPDATE_CREDENTIAL, + p1=P1.P1_ATTRIBUTE_VALUE, + p2=P2.P2_CREDENTIAL_CREDENTIAL, + data=attribute_value, + ): + pass + with self.backend.exchange_async( + cla=CLA, + ins=InsType.SIGN_UPDATE_CREDENTIAL, + p1=P1.P1_LENGTH_OF_PROOFS, + p2=P2.P2_CREDENTIAL_CREDENTIAL, + data=proof_length, + ): + pass + proof_chunks = split_message(proofs, MAX_APDU_LEN) + for i, chunk in enumerate(proof_chunks): + with self.backend.exchange_async( + cla=CLA, + ins=InsType.SIGN_UPDATE_CREDENTIAL, + p1=P1.P1_PROOFS, + p2=P2.P2_CREDENTIAL_CREDENTIAL, + data=chunk, + ): + pass + with self.backend.exchange_async( + cla=CLA, + ins=InsType.SIGN_UPDATE_CREDENTIAL, + p1=P1.P1_NONE, + p2=P2.P2_CREDENTIAL_ID_COUNT, + data=bytes.fromhex(f"{len(credential_id_list):02x}"), + ): + pass + for i, credential_id in enumerate(credential_id_list): + with self.backend.exchange_async( + cla=CLA, + ins=InsType.SIGN_UPDATE_CREDENTIAL, + p1=P1.P1_NONE, + p2=P2.P2_CREDENTIAL_ID, + data=credential_id, + ) as response: + if i == len(credential_id_list) - 1: + yield response + + @contextmanager + def sign_update_credential_part_4( + self, + threshold: bytes, + ) -> Generator[None, None, None]: + with self.backend.exchange_async( + cla=CLA, + ins=InsType.SIGN_UPDATE_CREDENTIAL, + p1=P1.P1_NONE, + p2=P2.P2_THRESHOLD, + data=threshold, + ) as response: + yield response + @contextmanager def sign_public_information_for_ip_part_1( self, chunks: List[bytes] diff --git a/tests/snapshots/flex/test_credential_update/1_sender/00000.png b/tests/snapshots/flex/test_credential_update/1_sender/00000.png new file mode 100644 index 0000000..794ad16 Binary files /dev/null and b/tests/snapshots/flex/test_credential_update/1_sender/00000.png differ diff --git a/tests/snapshots/flex/test_credential_update/1_sender/00001.png b/tests/snapshots/flex/test_credential_update/1_sender/00001.png new file mode 100644 index 0000000..7337565 Binary files /dev/null and b/tests/snapshots/flex/test_credential_update/1_sender/00001.png differ diff --git a/tests/snapshots/flex/test_credential_update/1_sender/00002.png b/tests/snapshots/flex/test_credential_update/1_sender/00002.png new file mode 100644 index 0000000..bc99818 Binary files /dev/null and b/tests/snapshots/flex/test_credential_update/1_sender/00002.png differ diff --git a/tests/snapshots/flex/test_credential_update/3_rem_credential/00000.png b/tests/snapshots/flex/test_credential_update/3_rem_credential/00000.png new file mode 100644 index 0000000..794ad16 Binary files /dev/null and b/tests/snapshots/flex/test_credential_update/3_rem_credential/00000.png differ diff --git a/tests/snapshots/flex/test_credential_update/3_rem_credential/00001.png b/tests/snapshots/flex/test_credential_update/3_rem_credential/00001.png new file mode 100644 index 0000000..e286e86 Binary files /dev/null and b/tests/snapshots/flex/test_credential_update/3_rem_credential/00001.png differ diff --git a/tests/snapshots/flex/test_credential_update/3_rem_credential/00002.png b/tests/snapshots/flex/test_credential_update/3_rem_credential/00002.png new file mode 100644 index 0000000..bc99818 Binary files /dev/null and b/tests/snapshots/flex/test_credential_update/3_rem_credential/00002.png differ diff --git a/tests/snapshots/flex/test_credential_update/4_threshold_and_sign/00000.png b/tests/snapshots/flex/test_credential_update/4_threshold_and_sign/00000.png new file mode 100644 index 0000000..d0cd8f6 Binary files /dev/null and b/tests/snapshots/flex/test_credential_update/4_threshold_and_sign/00000.png differ diff --git a/tests/snapshots/flex/test_credential_update/4_threshold_and_sign/00001.png b/tests/snapshots/flex/test_credential_update/4_threshold_and_sign/00001.png new file mode 100644 index 0000000..98b5d7f Binary files /dev/null and b/tests/snapshots/flex/test_credential_update/4_threshold_and_sign/00001.png differ diff --git a/tests/snapshots/flex/test_credential_update/4_threshold_and_sign/00002.png b/tests/snapshots/flex/test_credential_update/4_threshold_and_sign/00002.png new file mode 100644 index 0000000..b89973e Binary files /dev/null and b/tests/snapshots/flex/test_credential_update/4_threshold_and_sign/00002.png differ diff --git a/tests/snapshots/nanosp/test_credential_update/1_sender/00000.png b/tests/snapshots/nanosp/test_credential_update/1_sender/00000.png new file mode 100644 index 0000000..71ff391 Binary files /dev/null and b/tests/snapshots/nanosp/test_credential_update/1_sender/00000.png differ diff --git a/tests/snapshots/nanosp/test_credential_update/1_sender/00001.png b/tests/snapshots/nanosp/test_credential_update/1_sender/00001.png new file mode 100644 index 0000000..a8adec1 Binary files /dev/null and b/tests/snapshots/nanosp/test_credential_update/1_sender/00001.png differ diff --git a/tests/snapshots/nanosp/test_credential_update/1_sender/00002.png b/tests/snapshots/nanosp/test_credential_update/1_sender/00002.png new file mode 100644 index 0000000..5ffaef4 Binary files /dev/null and b/tests/snapshots/nanosp/test_credential_update/1_sender/00002.png differ diff --git a/tests/snapshots/nanosp/test_credential_update/1_sender/00003.png b/tests/snapshots/nanosp/test_credential_update/1_sender/00003.png new file mode 100644 index 0000000..daf8b4b Binary files /dev/null and b/tests/snapshots/nanosp/test_credential_update/1_sender/00003.png differ diff --git a/tests/snapshots/nanosp/test_credential_update/3_rem_credential/00000.png b/tests/snapshots/nanosp/test_credential_update/3_rem_credential/00000.png new file mode 100644 index 0000000..89f2a03 Binary files /dev/null and b/tests/snapshots/nanosp/test_credential_update/3_rem_credential/00000.png differ diff --git a/tests/snapshots/nanosp/test_credential_update/3_rem_credential/00001.png b/tests/snapshots/nanosp/test_credential_update/3_rem_credential/00001.png new file mode 100644 index 0000000..ea7effa Binary files /dev/null and b/tests/snapshots/nanosp/test_credential_update/3_rem_credential/00001.png differ diff --git a/tests/snapshots/nanosp/test_credential_update/4_threshold_and_sign/00000.png b/tests/snapshots/nanosp/test_credential_update/4_threshold_and_sign/00000.png new file mode 100644 index 0000000..9c38e41 Binary files /dev/null and b/tests/snapshots/nanosp/test_credential_update/4_threshold_and_sign/00000.png differ diff --git a/tests/snapshots/nanosp/test_credential_update/4_threshold_and_sign/00001.png b/tests/snapshots/nanosp/test_credential_update/4_threshold_and_sign/00001.png new file mode 100644 index 0000000..37a8b0d Binary files /dev/null and b/tests/snapshots/nanosp/test_credential_update/4_threshold_and_sign/00001.png differ diff --git a/tests/snapshots/nanox/test_credential_update/1_sender/00000.png b/tests/snapshots/nanox/test_credential_update/1_sender/00000.png new file mode 100644 index 0000000..71ff391 Binary files /dev/null and b/tests/snapshots/nanox/test_credential_update/1_sender/00000.png differ diff --git a/tests/snapshots/nanox/test_credential_update/1_sender/00001.png b/tests/snapshots/nanox/test_credential_update/1_sender/00001.png new file mode 100644 index 0000000..a8adec1 Binary files /dev/null and b/tests/snapshots/nanox/test_credential_update/1_sender/00001.png differ diff --git a/tests/snapshots/nanox/test_credential_update/1_sender/00002.png b/tests/snapshots/nanox/test_credential_update/1_sender/00002.png new file mode 100644 index 0000000..5ffaef4 Binary files /dev/null and b/tests/snapshots/nanox/test_credential_update/1_sender/00002.png differ diff --git a/tests/snapshots/nanox/test_credential_update/1_sender/00003.png b/tests/snapshots/nanox/test_credential_update/1_sender/00003.png new file mode 100644 index 0000000..daf8b4b Binary files /dev/null and b/tests/snapshots/nanox/test_credential_update/1_sender/00003.png differ diff --git a/tests/snapshots/nanox/test_credential_update/3_rem_credential/00000.png b/tests/snapshots/nanox/test_credential_update/3_rem_credential/00000.png new file mode 100644 index 0000000..89f2a03 Binary files /dev/null and b/tests/snapshots/nanox/test_credential_update/3_rem_credential/00000.png differ diff --git a/tests/snapshots/nanox/test_credential_update/3_rem_credential/00001.png b/tests/snapshots/nanox/test_credential_update/3_rem_credential/00001.png new file mode 100644 index 0000000..ea7effa Binary files /dev/null and b/tests/snapshots/nanox/test_credential_update/3_rem_credential/00001.png differ diff --git a/tests/snapshots/nanox/test_credential_update/4_threshold_and_sign/00000.png b/tests/snapshots/nanox/test_credential_update/4_threshold_and_sign/00000.png new file mode 100644 index 0000000..9c38e41 Binary files /dev/null and b/tests/snapshots/nanox/test_credential_update/4_threshold_and_sign/00000.png differ diff --git a/tests/snapshots/nanox/test_credential_update/4_threshold_and_sign/00001.png b/tests/snapshots/nanox/test_credential_update/4_threshold_and_sign/00001.png new file mode 100644 index 0000000..37a8b0d Binary files /dev/null and b/tests/snapshots/nanox/test_credential_update/4_threshold_and_sign/00001.png differ diff --git a/tests/snapshots/stax/test_credential_update/1_sender/00000.png b/tests/snapshots/stax/test_credential_update/1_sender/00000.png new file mode 100644 index 0000000..c53782c Binary files /dev/null and b/tests/snapshots/stax/test_credential_update/1_sender/00000.png differ diff --git a/tests/snapshots/stax/test_credential_update/1_sender/00001.png b/tests/snapshots/stax/test_credential_update/1_sender/00001.png new file mode 100644 index 0000000..fdda09a Binary files /dev/null and b/tests/snapshots/stax/test_credential_update/1_sender/00001.png differ diff --git a/tests/snapshots/stax/test_credential_update/1_sender/00002.png b/tests/snapshots/stax/test_credential_update/1_sender/00002.png new file mode 100644 index 0000000..c4c9687 Binary files /dev/null and b/tests/snapshots/stax/test_credential_update/1_sender/00002.png differ diff --git a/tests/snapshots/stax/test_credential_update/3_rem_credential/00000.png b/tests/snapshots/stax/test_credential_update/3_rem_credential/00000.png new file mode 100644 index 0000000..c53782c Binary files /dev/null and b/tests/snapshots/stax/test_credential_update/3_rem_credential/00000.png differ diff --git a/tests/snapshots/stax/test_credential_update/3_rem_credential/00001.png b/tests/snapshots/stax/test_credential_update/3_rem_credential/00001.png new file mode 100644 index 0000000..4a4d890 Binary files /dev/null and b/tests/snapshots/stax/test_credential_update/3_rem_credential/00001.png differ diff --git a/tests/snapshots/stax/test_credential_update/3_rem_credential/00002.png b/tests/snapshots/stax/test_credential_update/3_rem_credential/00002.png new file mode 100644 index 0000000..c4c9687 Binary files /dev/null and b/tests/snapshots/stax/test_credential_update/3_rem_credential/00002.png differ diff --git a/tests/snapshots/stax/test_credential_update/4_threshold_and_sign/00000.png b/tests/snapshots/stax/test_credential_update/4_threshold_and_sign/00000.png new file mode 100644 index 0000000..e8132c4 Binary files /dev/null and b/tests/snapshots/stax/test_credential_update/4_threshold_and_sign/00000.png differ diff --git a/tests/snapshots/stax/test_credential_update/4_threshold_and_sign/00001.png b/tests/snapshots/stax/test_credential_update/4_threshold_and_sign/00001.png new file mode 100644 index 0000000..c6f9b48 Binary files /dev/null and b/tests/snapshots/stax/test_credential_update/4_threshold_and_sign/00001.png differ diff --git a/tests/snapshots/stax/test_credential_update/4_threshold_and_sign/00002.png b/tests/snapshots/stax/test_credential_update/4_threshold_and_sign/00002.png new file mode 100644 index 0000000..49efffb Binary files /dev/null and b/tests/snapshots/stax/test_credential_update/4_threshold_and_sign/00002.png differ diff --git a/tests/test_credential_deployment.py b/tests/test_credential_deployment.py index e236425..275a386 100644 --- a/tests/test_credential_deployment.py +++ b/tests/test_credential_deployment.py @@ -67,7 +67,7 @@ def test_credential_deployment_new( test_name + f"/key{i}", True, False, - NavInsID.USE_CASE_CHOICE_CONFIRM + NavInsID.USE_CASE_CHOICE_CONFIRM, ) response = client.get_async_response() print("km------------response", response) @@ -100,7 +100,7 @@ def test_credential_deployment_new( test_name + "/last_key", True, False, - NavInsID.USE_CASE_REVIEW_CONFIRM + NavInsID.USE_CASE_REVIEW_CONFIRM, ) response = client.get_async_response() @@ -166,7 +166,7 @@ def test_credential_deployment_existing( test_name + f"/key{i}", True, False, - NavInsID.USE_CASE_CHOICE_CONFIRM + NavInsID.USE_CASE_CHOICE_CONFIRM, ) response = client.get_async_response() print("km------------response", response) @@ -188,7 +188,7 @@ def test_credential_deployment_existing( navigator, "details", default_screenshot_path, - test_name + "/last_key" + test_name + "/last_key", ) else: navigate_until_text_and_compare( @@ -199,7 +199,7 @@ def test_credential_deployment_existing( test_name + "/last_key", True, False, - NavInsID.USE_CASE_REVIEW_CONFIRM + NavInsID.USE_CASE_REVIEW_CONFIRM, ) response = client.get_async_response() @@ -208,3 +208,155 @@ def test_credential_deployment_existing( assert response.data == bytes.fromhex( "52be7b8e8da49716e1f355236429b4505a046f75f3ed67bb17854b15fecfbf382b1e1870e3c6a9e075ab1555c72fabd6c5e3422c1003714fb6667104f6f85400" ) + + +@pytest.mark.active_test_scope +def test_credential_update( + backend, firmware, navigator, test_name, default_screenshot_path +): + client = BoilerplateCommandSender(backend) + + keys = [ + bytes.fromhex( + "00f78929ec8a9819f6ae2e10e79522b6b311949635fecc3d924d9d1e23f8e9e1c3" + ), + ] + signature_threshold = bytes.fromhex( + "ff85d8a7aa296c162e4e2f0d6bfbdc562db240e28942f7f3ddef6979a1133b5c719ec3581869aaf88388824b0f6755e63c0000f013010001" + ) + ar_identity = bytes.fromhex( + "000f0301aca024ce6083d4956edad825c3721da9b61e5b3712606ba1465f7818a43849121bdb3e4d99624e9a74b9436cc8948d178b9b144122aa070372e3fadee4998e1cc21161186a3d19698ad245e10912810df1aaddda16a27f654716108e27758099" + ) + credential_dates = bytes.fromhex("07e40b07e10c0001") + attribute_tag = bytes.fromhex("010000000000000004") + attribute_value = bytes.fromhex("4a6f686e") + proof_length = bytes.fromhex("00000831") + proofs = bytes.fromhex( + "b8dc01d4fdd0c1b455e9a48285eac39ffc0a433929bbd29344016a2fdbd3892fabed9a607da37140ea2046aa7c924022a130cc78688e8174c4c244ea97461007b167f4c941585ff9b945eddff0f87942bf91bedc8d33355e7f3e09e4168c6ec98e3aa4b7b2e6a7807dd5cc6b057646115b82c65c97e3bc7a5898c61d99465ad655df2628d3d38cf97f7134fddfae366f80755e0dd926c54a74d05724da31c960aa5322e76a98af78e0d4ac161fd0af244a6e1068ed7661fdf0d4669c2cad41cd87641313d9ba06feb204f6c26ed208a7479daa933450a1fc293e792d6387724748a4d9403e7ff1f1deacbe41c949b06c000101a24eeaf8709e6e9930980d0a9ad6585760e8d9b58c04c6c73ce2245b70e237c86a61289dbb1cb59ff23e406a3426a92900000000000000019237d759d6dc3402310bc58ae027cbe65e4818f26fc2480a023d99a9af5403e8db6c834d6b964d42c9703959ed0121089a36989c8b92d83af2547472eeda05246837f7b3691732291a39ae7497147047000000020000000131f676f011cc5bde75b16440b051d0020070137bec8be3f167a961fbf99f647070298bc8c7f572bb3d5c8dc3b5d4c9f9750d54c85f8388e16e4bf0644c48c5666b02fec6f186c4b36994396f7023ef23c14535129c738664392d96e486eb15130000000259f75638807a180c00db02ef4dd3639132edbafc3663677494e8b1e2c51567a82e353e70c5e4c06213b09e5c528d8695cb5fd8ba97593c7ae9822f1835de801f18fce82ebf4839ca5062289eeb8ff36ded218404ccf7248008d1e72683b1138e4ab37e620b34b5793a2109e0734064ad03c5c5c14fb9920bf1f8c397b849b223000000085e17de448c17d47a4f715601fc66c5ddaea6154cd909795da984a099105af7486b2c1d617335d7a9d0d3db0c2c6a460e3680ff7b3d9d4bdc851494e90ff5101a1dc7323925c2e3f1c829199364456fc3dde9d770498b12a32d6b570c1c7221d859fe628d7e5a31711239e4d5eccc5bb7204f6e09cbfe00373e1042ac79dfbb7d4bf280fd53e8a0bac84bc6928c874ebf18905d50396083c7dd28455b68f37cf36f7b85b1027be4e1d2ccf8d2193e3436234bb4377724b0900db3e0f5c6466e2d083e97b933e49a9e0290b46b3acf81a01792954a1e1725793fb5ef4b596bd9a31c48285e3d056e79c6cd0094f8462b9e510c17d75d02639fbab819afbf1c84a55618932d52113990ef19268a2ebc0778b1b567e31a94264d6ac9cfc03867c24d50cfbf02f74dc8c9de3ac039e61ccd1865aa75d2a6f7627291fdae75c474ed3943d56c5a926eb6e6c121c550bcd4de0a0739021c50672407def5836c60d24ec762c839b6dee6cf937412ae6757d6894c8ff8dec2c0d6f3cd993e808965c84eb413d6022be0b1b1ccac25796adc0d95a2d7775e87a4d8085fa8a43f71008df77911b6f5b4ce5ee5d6f5412966ca47b20af751752fc0879fcc8a0d879acdbc8bcb00dbb93f0e10bcf36ccaf001191a4e4f47d40f59451fe4b376f2dd1d4d58854a55ed74ff2c5bb59c531e5651c99afb04318d84d936bc7ebba3823e108d7ae246157c7851016eb4bd9e74cd15af484be18b11115a2ef091e2439fce06426d4ff063dc86ffe0c5a3ea5f920fe3e8c946a5d0eacf4439f4beca8d8dc6311343f516444ef6779e3170a14b98ca26bbe516397a4f17b395178f473376a6944d0d1aba4fea8c66abaf63aef20f364c73f2c84cb3ef66f8ded751e7c8229b87f7276ba8474cced9521caafa0836e9cbb64aeaa86f20a7a38cb5353af7d642949fd59ec40100aa70e4ddbf823a5e89cb39328f7fcb2dd07b15652c3a027d5a8fc982abf950f355455937a5810cc0bb7e03b11db4bc8988b06c1467fe716a43b2ca13aa56f20bb651451fb838a93e8345a1b0f782edc37ad6b5d2719d2893e4585938f663d9df10a0bc8434b6dafd883b4c2b64b02a19b0c0d72ca2e5588e5df29963a423592917d86c372532fc65e1d2d85913c32e88466b01d5f5539079b1e2521858db1a9e9317c3ecdbed418a7caefa3da589436f619b2a617c078bf07ad753c27fb72b3731e459764264df77b1af2ca63644c2938055b0d73ceb1d8a2a50592ce06edf254709dd26f277f0af119c2e85b175070554b5e48101bdaed6df86e599f2673fae59d69eb3876c2ca7b96ae8f26428e13b45daa6b7fa5766adc5a45af6c300797e61a7c00cc186b3a0adb7ffa7f58eca72cb889c72347c1673846bdd28af281d2129934cc7347e92904422367bbc26000f70621f866f6fd5f1e9e14c65027a1179000000048415e12f31d099a3becd3c0a3304704980718faa6a2b73cad42ddbe0f0fd388c30bc668f3c70f52215bdf493ea6704b9864f06b92ccc8488090092ae5bc248ea3e20f77f59985ed062f46e8e3a2e1119fb97021fb20c432cfc8dd29a70a26b9bb80fa4e6b9c14e0299088f675e25a9f8c9192fb9bd8a672e71fb02a0275e9090f4e5fd3ea9d91daf731efcc696b24222b13931e1a82b858cd636ea690900c8e0608132bca8ec9bfa522112f8b9b3c6e790c68f9d0fd78750148dbc698e36d3f1a829a08d1dda9e66e552e282fade22759736b4677a1c23f5af0956923df8d0675adbaf6b2b7ee4e1ab4ffcb53828dcefb0a432370101feaccd66ef1cee80e2253f3a0d8024ff09d6ceef4742424a3a9f844e6854b32a5d4b66a71b3cc5c32e9cb9fe53a5959a4108090385951361357a61185398d361bab4804479a7712b07161a9b74e7760168cc70f5bbacc817ad208a7bc867a3e01f46e6832fb08ea77a4784b9e93b352a5a0d55646b099dfe7bd619625406828dc0a3d19da86c7550e44301c0decaab090bc3e146559388bcde1b4edc0fb76e152c937c4edb3c60179a8668a8baf73acda699950bf98d40dffc6d792a4702583dbc0afc34b6bb462e70f3" + ) + + credential_id_1 = bytes.fromhex( + "85d8a7aa296c162e4e2f0d6bfbdc562db240e28942f7f3ddef6979a1133b5c719ec3581869aaf88388824b0f6755e63c" + ) + credential_id_list = [credential_id_1] + + with client.credential_update_part_1( + data=bytes.fromhex( + "08000004510000000000000000000000000000000000000002000000000000000020a845815bd43a1999e90fbf971537a70392eb38f89e6bd32b3dd70e1a9551d7000000000000000a0000000000000064000000290000000063de5da71401" + ), + ): + if firmware.is_nano: + navigator.navigate_and_compare( + default_screenshot_path, + test_name + "/1_sender", + instructions_builder( + number_of_screens_until_confirm=3, backend=backend + ), + screen_change_before_first_instruction=False, + screen_change_after_last_instruction=False, + ) + else: + navigate_until_text_and_compare( + firmware, + navigator, + "Approve", + default_screenshot_path, + test_name + "/1_sender", + True, + False, + NavInsID.USE_CASE_CHOICE_CONFIRM, + ) + + for i, key in enumerate(keys): + with client.sign_update_credential_part_2( + key_index=bytes.fromhex(f"{i:02x}"), + number_of_keys=len(keys), + key=key, + ): + # Only navigate if it's not the last key + if firmware.is_nano and i < len(keys) - 1: + navigator.navigate_and_compare( + default_screenshot_path, + test_name + f"/2_key{i}", + instructions_builder( + number_of_screens_until_confirm=3, backend=backend + ), + screen_change_before_first_instruction=False, + screen_change_after_last_instruction=False, + ) + elif not firmware.is_nano and i < len(keys) - 1: + navigate_until_text_and_compare( + firmware, + navigator, + "Approve", + default_screenshot_path, + test_name + f"/2_key{i}", + True, + False, + NavInsID.USE_CASE_CHOICE_CONFIRM, + ) + + with client.sign_update_credential_part_3( + signature_threshold=signature_threshold, + ar_identity=ar_identity, + credential_dates=credential_dates, + attribute_tag=attribute_tag, + attribute_value=attribute_value, + proof_length=proof_length, + proofs=proofs, + credential_id_list=credential_id_list, + ): + if firmware.is_nano: + navigator.navigate_and_compare( + default_screenshot_path, + test_name + "/3_rem_credential", + instructions_builder( + number_of_screens_until_confirm=1, backend=backend + ), + screen_change_before_first_instruction=False, + screen_change_after_last_instruction=False, + ) + else: + navigate_until_text_and_compare( + firmware, + navigator, + "Approve", + default_screenshot_path, + test_name + "/3_rem_credential", + True, + False, + NavInsID.USE_CASE_CHOICE_CONFIRM, + ) + + with client.sign_update_credential_part_4( + threshold=bytes.fromhex(f"{len(credential_id_list):02x}"), + ): + if firmware.is_nano: + navigator.navigate_and_compare( + default_screenshot_path, + test_name + "/4_threshold_and_sign", + instructions_builder( + number_of_screens_until_confirm=1, backend=backend + ), + screen_change_before_first_instruction=False, + screen_change_after_last_instruction=False, + ) + else: + navigate_until_text_and_compare( + firmware, + navigator, + "Sign transaction", + default_screenshot_path, + test_name + "/4_threshold_and_sign", + True, + False, + NavInsID.USE_CASE_REVIEW_CONFIRM, + ) + + response = client.get_async_response().data + response_hex = response.hex() + print("response", response_hex) + assert ( + response_hex + == "e9f03b5e1d35447a3c1f088620edcc9ffb381fee716076d54971d02466be8f7edd16b999d903a7698d58ea1f79782576075d930654f3143c38704d7ef272be07" + )