From 43df0f31f3b86d65d837b469279f1e845aa30a31 Mon Sep 17 00:00:00 2001 From: Carlos Medeiros Date: Thu, 1 Aug 2024 15:49:25 +0100 Subject: [PATCH 1/2] update rslib with masp methods --- rs/src/lib.rs | 315 ++++++++++++++++++++++++++++++++++- rs/src/params.rs | 37 ++++ rs/src/utils.rs | 42 ++++- rs/tests/integration_test.rs | 127 ++++++++++---- 4 files changed, 484 insertions(+), 37 deletions(-) diff --git a/rs/src/lib.rs b/rs/src/lib.rs index 6d57466a..d1c7471c 100644 --- a/rs/src/lib.rs +++ b/rs/src/lib.rs @@ -30,11 +30,16 @@ use std::collections::HashMap; pub use ledger_zondax_generic::LedgerAppError; mod params; -use params::SALT_LEN; pub use params::{ - InstructionCode, ADDRESS_LEN, CLA, ED25519_PUBKEY_LEN, PK_LEN_PLUS_TAG, SIG_LEN_PLUS_TAG, + InstructionCode, KeyResponse, NamadaKeys, ADDRESS_LEN, CLA, ED25519_PUBKEY_LEN, + PK_LEN_PLUS_TAG, SIG_LEN_PLUS_TAG, +}; +use params::{KEY_LEN, SALT_LEN}; +use utils::{ + ResponseAddress, ResponseGetConvertRandomness, ResponseGetOutputRandomness, + ResponseGetSpendRandomness, ResponseMaspSign, ResponseProofGenKey, ResponsePubAddress, + ResponseSignature, ResponseSpendSignature, ResponseViewKey, }; -use utils::{ResponseAddress, ResponseSignature}; use std::convert::TryInto; use std::str; @@ -311,4 +316,308 @@ where raw_sig && wrapper_sig } + + /// Retrieve masp keys from the Namada app + pub async fn retrieve_keys( + &self, + path: &BIP44Path, + key_type: NamadaKeys, + require_confirmation: bool, + ) -> Result> { + let serialized_path = path.serialize_path().unwrap(); + let p1: u8 = if require_confirmation { 1 } else { 0 }; + + let p2: u8 = match key_type { + NamadaKeys::PublicAddress => 0, + NamadaKeys::ViewKey => 1, + NamadaKeys::ProofGenerationKey => 2, + }; + + let command = APDUCommand { + cla: CLA, + ins: InstructionCode::GetKeys as _, + p1, + p2, + data: serialized_path, + }; + + let response = self + .apdu_transport + .exchange(&command) + .await + .map_err(LedgerAppError::TransportError)?; + + match response.error_code() { + Ok(APDUErrorCode::NoError) => {} + Ok(err) => { + return Err(NamError::Ledger(LedgerAppError::AppSpecific( + err as _, + err.description(), + ))) + } + Err(err) => { + return Err(NamError::Ledger(LedgerAppError::AppSpecific( + err, + "[APDU_ERROR] Unknown".to_string(), + ))) + } + } + + let response_data = response.apdu_data(); + match key_type { + NamadaKeys::PublicAddress => Ok(KeyResponse::Address(ResponsePubAddress { + public_address: response_data[..KEY_LEN].try_into().unwrap(), + })), + NamadaKeys::ViewKey => { + let (view_key, rest) = response_data.split_at(2 * KEY_LEN); + let (ovk, rest) = rest.split_at(KEY_LEN); + let (ivk, _) = rest.split_at(KEY_LEN); + Ok(KeyResponse::ViewKey(ResponseViewKey { + view_key: view_key.try_into().unwrap(), + ovk: ovk.try_into().unwrap(), + ivk: ivk.try_into().unwrap(), + })) + } + NamadaKeys::ProofGenerationKey => { + let (ak, rest) = response_data.split_at(KEY_LEN); + let (nsk, _) = rest.split_at(KEY_LEN); + Ok(KeyResponse::ProofGenKey(ResponseProofGenKey { + ak: ak.try_into().unwrap(), + nsk: nsk.try_into().unwrap(), + })) + } + } + } + + /// Get Randomness for Spend + pub async fn get_spend_randomness( + &self, + ) -> Result> { + let arr: &[u8] = &[]; + let command = APDUCommand { + cla: CLA, + ins: InstructionCode::GetSpendRandomness as _, + p1: 0x00, + p2: 0x00, + data: arr, // Send empty data + }; + + let response = self + .apdu_transport + .exchange(&command) + .await + .map_err(LedgerAppError::TransportError)?; + + match response.error_code() { + Ok(APDUErrorCode::NoError) => {} + Ok(err) => { + return Err(NamError::Ledger(LedgerAppError::AppSpecific( + err as _, + err.description(), + ))) + } + Err(err) => { + return Err(NamError::Ledger(LedgerAppError::AppSpecific( + err, + "[APDU_ERROR] Unknown".to_string(), + ))) + } + } + + let response_data = response.apdu_data(); + if response_data.len() < 2 * KEY_LEN { + return Err(NamError::Ledger(LedgerAppError::InvalidMessageSize)); + } + + let (rcv, rest) = response_data.split_at(KEY_LEN); + let (alpha, _) = rest.split_at(KEY_LEN); + Ok(ResponseGetSpendRandomness { + rcv: rcv.try_into().unwrap(), + alpha: alpha.try_into().unwrap(), + }) + } + + /// Get Randomness for convert + pub async fn get_convert_randomness( + &self, + ) -> Result> { + let arr: &[u8] = &[]; + let command = APDUCommand { + cla: CLA, + ins: InstructionCode::GetConvertRandomness as _, + p1: 0x00, + p2: 0x00, + data: arr, // Send empty data + }; + + let response = self + .apdu_transport + .exchange(&command) + .await + .map_err(LedgerAppError::TransportError)?; + + match response.error_code() { + Ok(APDUErrorCode::NoError) => {} + Ok(err) => { + return Err(NamError::Ledger(LedgerAppError::AppSpecific( + err as _, + err.description(), + ))) + } + Err(err) => { + return Err(NamError::Ledger(LedgerAppError::AppSpecific( + err, + "[APDU_ERROR] Unknown".to_string(), + ))) + } + } + + let response_data = response.apdu_data(); + if response_data.len() < KEY_LEN { + return Err(NamError::Ledger(LedgerAppError::InvalidMessageSize)); + } + + let (rcv, _) = response_data.split_at(KEY_LEN); + Ok(ResponseGetConvertRandomness { + rcv: rcv.try_into().unwrap(), + }) + } + + /// Get Randomness for output + pub async fn get_output_randomness( + &self, + ) -> Result> { + let arr: &[u8] = &[]; + let command = APDUCommand { + cla: CLA, + ins: InstructionCode::GetOutputRandomness as _, + p1: 0x00, + p2: 0x00, + data: arr, // Send empty data + }; + + let response = self + .apdu_transport + .exchange(&command) + .await + .map_err(LedgerAppError::TransportError)?; + + match response.error_code() { + Ok(APDUErrorCode::NoError) => {} + Ok(err) => { + return Err(NamError::Ledger(LedgerAppError::AppSpecific( + err as _, + err.description(), + ))) + } + Err(err) => { + return Err(NamError::Ledger(LedgerAppError::AppSpecific( + err, + "[APDU_ERROR] Unknown".to_string(), + ))) + } + } + + let response_data = response.apdu_data(); + if response_data.len() < 2 * KEY_LEN { + return Err(NamError::Ledger(LedgerAppError::InvalidMessageSize)); + } + + let (rcv, rest) = response_data.split_at(KEY_LEN); + let (rcm, _) = rest.split_at(KEY_LEN); + Ok(ResponseGetOutputRandomness { + rcv: rcv.try_into().unwrap(), + rcm: rcm.try_into().unwrap(), + }) + } + + /// Get Spend signature + pub async fn get_spend_signature(&self) -> Result> { + let arr: &[u8] = &[]; + let command = APDUCommand { + cla: CLA, + ins: InstructionCode::ExtractSpendSignature as _, + p1: 0x00, + p2: 0x00, + data: arr, // Send empty data + }; + + let response = self + .apdu_transport + .exchange(&command) + .await + .map_err(LedgerAppError::TransportError)?; + + match response.error_code() { + Ok(APDUErrorCode::NoError) => {} + Ok(err) => { + return Err(NamError::Ledger(LedgerAppError::AppSpecific( + err as _, + err.description(), + ))) + } + Err(err) => { + return Err(NamError::Ledger(LedgerAppError::AppSpecific( + err, + "[APDU_ERROR] Unknown".to_string(), + ))) + } + } + + let response_data = response.apdu_data(); + if response_data.len() < 2 * KEY_LEN { + return Err(NamError::Ledger(LedgerAppError::InvalidMessageSize)); + } + + let (rbar, rest) = response_data.split_at(KEY_LEN); + let (sbar, _) = rest.split_at(KEY_LEN); + Ok(ResponseSpendSignature { + rbar: rbar.try_into().unwrap(), + sbar: sbar.try_into().unwrap(), + }) + } + + /// Sign Masp signing + pub async fn sign_masp( + &self, + path: &BIP44Path, + blob: &[u8], + ) -> Result> { + let first_chunk = path.serialize_path().unwrap(); + + let start_command = APDUCommand { + cla: CLA, + ins: InstructionCode::SignMasp as _, + p1: ChunkPayloadType::Init as u8, + p2: 0x00, + data: first_chunk, + }; + + let response = + >::send_chunks(&self.apdu_transport, start_command, blob).await?; + + match response.error_code() { + Ok(APDUErrorCode::NoError) => {} + Ok(err) => { + return Err(NamError::Ledger(LedgerAppError::AppSpecific( + err as _, + err.description(), + ))) + } + Err(err) => { + return Err(NamError::Ledger(LedgerAppError::AppSpecific( + err, + "[APDU_ERROR] Unknown".to_string(), + ))) + } + } + + // Transactions is signed - Retrieve signatures + let rest = response.apdu_data(); + let (hash, _) = rest.split_at(KEY_LEN); + + Ok(ResponseMaspSign { + hash: hash.try_into().unwrap(), + }) + } } diff --git a/rs/src/params.rs b/rs/src/params.rs index 36ce7f6d..32075829 100644 --- a/rs/src/params.rs +++ b/rs/src/params.rs @@ -17,9 +17,13 @@ #![deny(unused_import_braces, unused_qualifications)] #![deny(missing_docs)] +use crate::utils::{ResponseProofGenKey, ResponsePubAddress, ResponseViewKey}; + /// App identifier pub const CLA: u8 = 0x57; +/// MASP keys len +pub const KEY_LEN: usize = 32; /// Public Key Length pub const ED25519_PUBKEY_LEN: usize = 32; /// Public Key + Tag Length @@ -41,7 +45,40 @@ pub enum InstructionCode { GetAddressAndPubkey = 1, /// Instruction to sign a transaction Sign = 2, + /// Instruction to retrieve MASP keys + GetKeys = 3, + /// Instruction to generate spend randomness values + GetSpendRandomness = 4, + /// Instruction to generate output randomness values + GetOutputRandomness = 5, + /// Instruction to generate spend convert values + GetConvertRandomness = 6, + /// Instruction to sign masp + SignMasp = 7, + /// Instruction to retrieve spend signatures + ExtractSpendSignature = 8, /// Instruction to retrieve a signed section GetSignature = 0x0a, } + +#[derive(Clone, Debug)] +/// Masp keys return types +pub enum NamadaKeys { + /// Public address key + PublicAddress = 0x00, + /// View key + ViewKey = 0x01, + /// Proof generation key + ProofGenerationKey = 0x02, +} + +/// Types of Keys Response +pub enum KeyResponse { + /// Address response + Address(ResponsePubAddress), + /// View key response + ViewKey(ResponseViewKey), + /// Proof generation key response + ProofGenKey(ResponseProofGenKey), +} diff --git a/rs/src/utils.rs b/rs/src/utils.rs index 125009b3..748b299e 100644 --- a/rs/src/utils.rs +++ b/rs/src/utils.rs @@ -21,7 +21,9 @@ use std::error::Error; const HARDENED: u32 = 0x80000000; -use crate::params::{ADDRESS_LEN, ED25519_PUBKEY_LEN, PK_LEN_PLUS_TAG, SALT_LEN, SIG_LEN_PLUS_TAG}; +use crate::params::{ + ADDRESS_LEN, ED25519_PUBKEY_LEN, KEY_LEN, PK_LEN_PLUS_TAG, SALT_LEN, SIG_LEN_PLUS_TAG, +}; use byteorder::{LittleEndian, WriteBytesExt}; pub struct ResponseAddress { @@ -41,6 +43,44 @@ pub struct ResponseSignature { pub wrapper_indices: Vec, } +pub struct ResponsePubAddress { + pub public_address: [u8; ED25519_PUBKEY_LEN], +} + +pub struct ResponseViewKey { + pub view_key: [u8; 2 * KEY_LEN], + pub ivk: [u8; KEY_LEN], + pub ovk: [u8; KEY_LEN], +} + +pub struct ResponseProofGenKey { + pub ak: [u8; KEY_LEN], + pub nsk: [u8; KEY_LEN], +} + +pub struct ResponseGetSpendRandomness { + pub rcv: [u8; KEY_LEN], + pub alpha: [u8; KEY_LEN], +} + +pub struct ResponseGetOutputRandomness { + pub rcv: [u8; KEY_LEN], + pub rcm: [u8; KEY_LEN], +} + +pub struct ResponseGetConvertRandomness { + pub rcv: [u8; KEY_LEN], +} + +pub struct ResponseSpendSignature { + pub rbar: [u8; KEY_LEN], + pub sbar: [u8; KEY_LEN], +} + +pub struct ResponseMaspSign { + pub hash: [u8; KEY_LEN], +} + /// BIP44 Path pub struct BIP44Path { /// BIP44 path in string format ("m/44'/283'/0/0/0") diff --git a/rs/tests/integration_test.rs b/rs/tests/integration_test.rs index bc52b198..a5457af7 100644 --- a/rs/tests/integration_test.rs +++ b/rs/tests/integration_test.rs @@ -21,12 +21,12 @@ extern crate ledger_namada_rs; -use hex::FromHex; -use ledger_namada_rs::{BIP44Path, NamadaApp, PK_LEN_PLUS_TAG}; +//use hex::FromHex; +use ledger_namada_rs::{BIP44Path, KeyResponse, NamadaApp, NamadaKeys, PK_LEN_PLUS_TAG}; use ledger_transport_hid::{hidapi::HidApi, TransportNativeHID}; use once_cell::sync::Lazy; use serial_test::serial; -use std::collections::HashMap; +//use std::collections::HashMap; static HIDAPI: Lazy = Lazy::new(|| HidApi::new().expect("Failed to create Hidapi")); @@ -81,47 +81,108 @@ async fn address() { println!("Address String Format {:?}", response.address_str); } +// #[tokio::test] +// #[serial] +// async fn sign_verify() { +// let app = app(); + +// // Bond transaction blob +// let blob_hex_string = "1d0000006c6f63616c6e65742e6664633665356661643365356535326433662d300023000000323032332d31312d31365431343a33313a31322e3030383437393437392b30303a303029e3fd2d0a8c786d5318be88f0be06629152ac26628396e28350f7c5b81b1d58f09f9bf315fe3b244703f3695cafff63b67156f799dc5c0742d1612cdd4897be0101000000000000000000000000000000000000000000000000000000000000000032fdd4e57f56519541491312d4e9089032244eca0048998ffa0340c473b72dad3604abd76581e71e4a334d0708ef754a0adcec66d80300000000000000a861000000000000000200000002b3078bd88b010000007c7a739c83e943d4a56a0fd4e4c52a9edc0d66d9105324bcc909619857a6683b010c00000074785f626f6e642e7761736d00b3078bd88b0100004b00000000f2d1fbf5a690f8ab12cfa6166425bec4d7569bb400e9a435000000000000000000000000000000000000000000000000000000000100ba4c9645a23343896227110a902af84e7b4a4bb3".as_bytes(); +// let blob = Vec::from_hex(blob_hex_string).expect("Invalid hexadecimal string"); + +// let mut section_hashes: HashMap> = HashMap::new(); +// section_hashes.insert( +// 0, +// hex::decode("5b693f86a6a8053b79effacd031e2367a1d35cc64988795768920b2965013742").unwrap(), +// ); +// section_hashes.insert( +// 1, +// hex::decode("29e3fd2d0a8c786d5318be88f0be06629152ac26628396e28350f7c5b81b1d58").unwrap(), +// ); +// section_hashes.insert( +// 2, +// hex::decode("f09f9bf315fe3b244703f3695cafff63b67156f799dc5c0742d1612cdd4897be").unwrap(), +// ); +// section_hashes.insert( +// 0xff, +// hex::decode("c7fec5279e22792a9cad6346f8933c1b2249043e1a03c835030d4e71dfbac3e0").unwrap(), +// ); + +// let path = BIP44Path { +// path: "m/44'/877'/0'/0'/0'".to_string(), +// }; +// let show_on_screen = false; +// // First, get public key +// let response_address = app +// .get_address_and_pubkey(&path, show_on_screen) +// .await +// .unwrap(); + +// // Sign and retrieve signatures +// let response = app.sign(&path, &blob).await.unwrap(); +// let signature_ok = +// app.verify_signature(&response, section_hashes, &response_address.public_key); + +// assert_eq!(signature_ok, true); +// } + #[tokio::test] #[serial] -async fn sign_verify() { +async fn get_masp_addr() { let app = app(); + let path = BIP44Path { + path: "m/44'/877'/0'/0'/0'".to_string(), + }; - // Bond transaction blob - let blob_hex_string = "1d0000006c6f63616c6e65742e6664633665356661643365356535326433662d300023000000323032332d31312d31365431343a33313a31322e3030383437393437392b30303a303029e3fd2d0a8c786d5318be88f0be06629152ac26628396e28350f7c5b81b1d58f09f9bf315fe3b244703f3695cafff63b67156f799dc5c0742d1612cdd4897be0101000000000000000000000000000000000000000000000000000000000000000032fdd4e57f56519541491312d4e9089032244eca0048998ffa0340c473b72dad3604abd76581e71e4a334d0708ef754a0adcec66d80300000000000000a861000000000000000200000002b3078bd88b010000007c7a739c83e943d4a56a0fd4e4c52a9edc0d66d9105324bcc909619857a6683b010c00000074785f626f6e642e7761736d00b3078bd88b0100004b00000000f2d1fbf5a690f8ab12cfa6166425bec4d7569bb400e9a435000000000000000000000000000000000000000000000000000000000100ba4c9645a23343896227110a902af84e7b4a4bb3".as_bytes(); - let blob = Vec::from_hex(blob_hex_string).expect("Invalid hexadecimal string"); + let show_on_screen = true; + let response = app + .retrieve_keys(&path, NamadaKeys::PublicAddress, show_on_screen) + .await + .unwrap(); - let mut section_hashes: HashMap> = HashMap::new(); - section_hashes.insert( - 0, - hex::decode("5b693f86a6a8053b79effacd031e2367a1d35cc64988795768920b2965013742").unwrap(), - ); - section_hashes.insert( - 1, - hex::decode("29e3fd2d0a8c786d5318be88f0be06629152ac26628396e28350f7c5b81b1d58").unwrap(), - ); - section_hashes.insert( - 2, - hex::decode("f09f9bf315fe3b244703f3695cafff63b67156f799dc5c0742d1612cdd4897be").unwrap(), - ); - section_hashes.insert( - 0xff, - hex::decode("c7fec5279e22792a9cad6346f8933c1b2249043e1a03c835030d4e71dfbac3e0").unwrap(), - ); + if let KeyResponse::Address(ref address_response) = response { + assert_eq!(32, address_response.public_address.len()); + } else { + panic!("Expected KeyResponse::Address"); + } +} +#[tokio::test] +#[serial] +async fn get_masp_view_key() { + let app = app(); let path = BIP44Path { path: "m/44'/877'/0'/0'/0'".to_string(), }; - let show_on_screen = false; - // First, get public key - let response_address = app - .get_address_and_pubkey(&path, show_on_screen) + + let show_on_screen = true; + let response = app + .retrieve_keys(&path, NamadaKeys::ViewKey, show_on_screen) .await .unwrap(); - // Sign and retrieve signatures - let response = app.sign(&path, &blob).await.unwrap(); - let signature_ok = - app.verify_signature(&response, section_hashes, &response_address.public_key); + if let KeyResponse::ViewKey(ref view) = response { + assert_eq!(2 * 32, view.view_key.len()); // Updated to check the length of view_key + } else { + panic!("Expected KeyResponse::ViewKey"); // Ensured the panic message is correct + } +} + +#[tokio::test] +#[serial] +async fn sign_masp() { + let app = app(); + let path = BIP44Path { + path: "m/44'/877'/0'/0'/0'".to_string(), + }; + let blob_hex_string = "150000005470655f3635467456785f5151437765455f5f5f5f0023000000393438302d31302d32335430353a33343a35372e3437393130313032372b30303a30300100000079b23ce752aca467c03cb7d14ff1a828e11aa72a8e8d7413d33f84c5eed1a29ed38b13039803e18164076a86394c75f6fac62f49466653dbffabaac638e7b26100000000000000000000000000000000000000000000000000000000000000000001efea3e1f11cc2f0b000000000000000000000000000000000000000000000000f90025bb32ca01580961be84ce307b9a61a90acb3b8c00fb2099dab5546e4cb122ed7204d0d334de930ba4f946ce4892562605e688559e83ff0a0bea63bcdc06000000022e1637aa4062b46c004d20381a4ea0f2e226a89d96a12e6dbfe999117b9e3b6bfc483ad9608719db1a011000000074785f7472616e736665722e7761736d00d6cd4bfade149c76290000000000000000000000010903dc1f3246f6dc11c423b63af54a8dcbc4669ac2ddc6474159b90f56a7d5c704020000000a27a726a675ffe90000000042864ae90000015a963918c623d53eefd5299d5539a462ee8f0d44bba874af01477677c51bf99ecfac7e5a8222a5506464d41ff45bf1d441997bf9f940fb11c6733031442441517d9d1d8cd30b1e26100d85ccc6acf8cdd8de2f90e0deb64660e47eccfe23e2020002696aab971e409a78348da5386e5b1e0140661681f9c46424d06c9d61fcfd1015db1655b60c7834aebfe133695f92956eb2980ebf7480819581032c2e9449e072303fd2544b939e290d0eb701f6c49ee0f59d153bb117ded8fffdb98c923f1d08f72af0e1df8eaf28a757476fc71d8cfb6bf484631dc6f65f4dc0dcbac231c8834058255b1b2860ed799ca952ebfe96352475f595f2787b54a2741b6558e66207c35a7e27629ea52670c860c0fc7dc0a0a488942c1d2e4078265da8efd524d9a5c9dc1cb3423bb8da6adba0984b156fafe774521da3e67c90607de6c9eec02d21bda68b7914f5d78a93536fac3fdcea020b8f6d79d686bfd905b2800a38c55008587a416e21d21329cc57bb038b67f5184640b5974b13f749265fff9a6b49e057b186865545d1e28e0a85e756404c36a831f13932396da5da0ecf45e8bcc4e2f40eb8dc06c3029fc726eddf556f6e3acf6b5f6de4a5d30f22c23ff131d9105795879b18b3f73375140d989cfe388aea4232b7610b9476f8cac497b2b7cc886430f304edbd79b6b051253f24da83ebbd3ab46840255039bc264671aa648884c3f2297a54746c0f5ab0ec0462f2840abd47203e84541c74ab9fbf0129722f7be59c82c0f06a59dd645f9c8b3188e3c4c69eef926aca45e58d811afaa12623508f48e62f78e243187c3b291d214e132c9531d66f822597b4967bab0999fb4763fba369fe3ec1435665b896d3156a2dc06c74388afcf31bef9b6da0ad5ad4a7a37e4125cd82857fdd7f2f9959d98b97a4a851807e48917e02ac38c2eb3ea20eaf610276b34da046bc7be2a61a43149e234881fb23b6ede9b0a1476f9452fe86d4e1de0212f26adfa10f992303a9da93dc3be636ed3048583a93139124238366cbc9e43c282826304ae655bde0f24582819edc119879bf24eb63a363565e02b868f647148d7c3736a7628cc41e7d967a51509bc316fe895ff405449d712ae0a33269450163561a4697116d109a8532e528ca9b79240ab32503b52ea91694bb5dce7828c4556c9e77337d45c41810861ec1aa38a018f62496d7cbf33a80ae81b4b86ada85a4faf96c9f2d03a95c128e54602a4b459ddf38300bdd66631e40a4a5521cc80677420c5468be8c579ce1e089b8739965967334b438188cd2662f3faa85af6b88cacab00d250091c7233d92e7569a5d1526b82ea806f9b7680f32b4436e62c2c4028aa1152b619a6baa0f8bc6472f17dbe2e7b6288254c52bfcb146b3279690472f92f89fc86589736b660f3734d52251463f63cb52d0db17d2dec3c87ba1f99a43fb5f0084719ae306aa0bf21deea925d3945afce2fb0d361760d6baa68936d10364a471a44276a47fb879927c7612c957700359f4a40bec31eca10d901e3ada7816c346723d16d445403ccd9ebfcd0e5c58f066d9686f8a352aa174846e358f191dd265e165ac9a62d6c3f0c2d177ee598fcb3589cb4a94e95a6b3dabca7e833f854f4bdb6243492fad78432543c689b2161ec80c9f3db6b01693fe01e64cb10e50e561e8ff5309d428f972f23c856b4aca8e73a6ac11648c2ffd8c3de167370b8a9eb0b7034e4b517e77742fc66e67269825fcbdb294a98efc59c8371bf01eb7f0a764a9d7b7692cc22a3e586f1a73fbcf8d62d4d9badbcf9aefdfcbb2394fc3382572b3b7e2cddaa0a2ecb6ac035e2e2867ead7af1410746ed43839a2aa00e6af303cd48f9681bacd26033541d85ec47816ba455d193421c7dae04eebf54cf92cc3b3577fa17d04ea4a063093c07d8c8e23b3e361c4c30cdcd623aa94dedf703d0b5605dc4a884e09ab63fb744c8959137f55820a290adb38d9d6a4ffe613e57c5fbdab9f8b5a07663cdb644adffb02fda036fbb7cc222869cae509928aa73480e79e440ec3fe5f4adea8764cb03669454054f653ba93e54703d4b62161db55a9b57ea0d013b64b283fd8c9df4f2e7349147feccefd48c6088f1deb3653fcc03512ccbdfff076a70dfd9453e7703890e022aa22ae752833987c16eeb695dfeed0dfb4b31fdacf8d127634cd718ce1dd414d1aa172be28074ea5f8bf2db8672fcd45a24105ea3deafc67323f9d12ea12489c818b1c0ae7dd79d8ad8ceb3a301254c966a82da54c7611c7c5677c307432727f7902898837a2490db693b25f56512cb3618ab24cd2a1d5e0b07c5b8de5dbe69e5c6cd3a1b5d9262b942f93356ca3e7a33d785d3100194712c4b62f4f95b49cc3129bcf867a486df43793999649dd580bcfefa7182697f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb897f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb9ef0b395bfc0bc14bde3cf7d4591eb66096944af394f6171debaf8efcdbf4a434f851210eb394899802c91b0e88afac3c564ba641a5dd8c24a7bff12b59d120697f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb897f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb897f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb6e8647b704ba7bdb643b5409cbc1623f52ce7acfd3ff4a3a4cb12a5548161a57856ddc809f34df26774326ac7bc4937a852c3aed01b12a81e096f9516b53db03050903dc1f3246f6dc11c423b63af54a8dcbc4669ac2ddc6474159b90f56a7d5c70100000002089fe2c139ce51f0ca36115e113c8fd60a41248132f0030118ae2a75e04246d5010000000000000000000000000000000100000000000000000000002e864ae942864ae9000000000000000001194712c4b62f4f95b49cc3129bcf867a486df43793999649dd580bcfefa718262e864ae90000010000000000000000000000009980aef6a062435f203fd1dba8cc1570bc84720519361351766d13625205ad07f71fa3b0f8e439251eb7f7931dbd08f5489c14b063df7bb51f110af9f34ac75ac53f49bb1035144d3d348ea1c39062727e9d208351204539254df29257dd04d7887ae5c99ef2e3e06ebcc172c2383aca81272da1f482abd1a1a91182a0bf475120487240083a18b885f9db835a41782832513402948e78f74a27ea8d4ac0db53123d58b6551d4430a6aa73090cb40a3928ba64f4c2414a3551dea5f599506d12795a06583ee8d676a3dba83c000000000000003e7a3f5fffe13ef1d78e5f3875d6992b6ccb760135bcb5be06d3f608af61e5000823bd80954a39a49d89d6255743dad368a7eb6f3073cacc2f6d9878b07d395f02472f4be8a7d92ca5a32908b12bc3b7d9f771678e744df7b0e2166147e35c7e0e2020de43f9cb72ec5b01c93aff1981a6cb7765b3e0c60ecdd4f0ddc1f1dda252ff0e20ad15f9b7057e4431f40b17d3cc76194d8339b1ddd9d80b20352002634663642e2089fd643bbfeef5b486e4e29e1c99d72c29944791c32fc225396b59318681b633208ef64e2cbb03d5af593244b253abc3e94db3b9150596e17303940d4eb2d5781a20a5461d4e8bd352703204beb6277e50a2c27e7779f7ab98fd45ceb0bba5c1b901203b52fb113249110b4566887d79a9693c3be69572a5b90b690702066e97ef155c204b07ba48cb4a793c01dfeb6392195b6493f3ceed52b5cea7df7279220e967e47204147f5d495d644e9c246093bdba51a94d44de39bb435f3410b52969570babe6d20b522e12ee1a1aa449be27411bbf4f8bdf90a8a816b7144f28991fa307644541b20d88bbcd3447046ef164ce336bdb9d6d29f4367d2f8aa7d39644e87c9c1ecca05202d7708b49a8ab745c2f51f638649c6a455842a6f4e040aae4d9885546337245920897423682b6d8f56fce75bf9c4a7f70f35dfa7386e554e7c561a62a835c3a3662049c2d8eff3e9c0a5a2017de57ab4e2c12eea2cf06228127f26580f4fa9af5623206ed767be9c66da7d6f7eba511871d9da61456026b7f310e15e3359ac41ec926020dd0e078b30ad16780690abae311be0130c2a9a030d0d65c8f12aec3264ed853b208934595bab6108f9b2e6fa75d4e1d285eb79791c5e7610358acd626a4b17022120b93879c9b8476d6b3952933c83a07ac6aeeb01f6bc971b6740da7614a47da958203a6ac56a4149e8c9bd8119e3ab6fa7780bda6fc14d6119c416a11a1bc1c0b60d2048917eaa9b4c094d69ec54970475d3df466a984ee9aed707970c69bc958f6e61209eed88e4f9bb67d455f9aebdb6ab4ef8b566b03f230804c7f58214043bd4e471202cd2e15a6e521b4ff874c7261fcba80b7782526f236bf73435ce20eb136d4c33203ea72374fe684e6a8eb5d4980633218da196cab396fcdddf6831953298f3e45520798e3416956611fa66571e10e50b8b2c0abf537f16afc725ced4ece6b279142420806ab1a3c089454e16575ceece1e3aefee2a6184255e18a2343fb7feb86b7e6d204e8e59d04c3f4469e9d58483fc8539db868cf2334f4257121ad6f80db6c9702d204c66cea9b58243efbe2e62d1da3a03a48cfbce68ef212b3c77acb1e12c5ab962205b5714543c02aa922a6620e12e901943fc5b03bb9ae1586c002d639570326707203aa41a68aac5b5e125616c1c4efb4a00e08ca4f8e65e66a1470d7c47c72a140f2039cf8d1399cea0bbb22c31ff1ed14be62acb70e75f13aa0757c29d76b943a53e206772ffd2b185aac6d10dc02551d9de9e7094b5548e9e13a833da8dc477a1022020325aea4964041359acb6d15fa724089dd7242a7a61b1d9db50983e402d88ff1d2001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000cbb7d0983d49b7c16f336f2a866d51582bf12100a546969c93b781cfe64d9e79923a1614f6653111eb06db090cb40a3928ba64f4c2414a3551dea5f599506d12795a06583ee8d676a3dba83c00000000000000d2dee78dacb6403454640abb0606e2fe1bfb18b72e4f597b21213506cfc4c51d2a866d51582bf12100a546969c93b781cfe64d9e79923a1614f6653111eb06dbf600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030500000050f0e1d591ae077b20a0b9641c22ae484ff6d16049a7869208cef66b6eff627e79b23ce752aca467c03cb7d14ff1a828e11aa72a8e8d7413d33f84c5eed1a29ed38b13039803e18164076a86394c75f6fac62f49466653dbffabaac638e7b26158ff6c68e7f4be532aa04b365224038dc1a5d095babf111537b7ffe69dde9ecf08e0961f7133564f30146128683dab4cea1de52334f7fed4d01711700be34a09000147b37cc9e907a9da3286a95cf5498c6948bda0fc02000000d00058a4a0f36e326f08285414ee29a749ddd339500b20045f27914f92585ecc7910b13645bad82237df33aa1b69e82476cac0817d2ff508f3b39c22a77e99d9ea07da00b4f150a8c7af85018135957c8d3759347ee3253b125b0804da0df1aa5f1a9228fc55131a4a62cfb730598362f1b55b66c3dfc890a443e7a5e90b2c5f7105d205030500000050f0e1d591ae077b20a0b9641c22ae484ff6d16049a7869208cef66b6eff627e79b23ce752aca467c03cb7d14ff1a828e11aa72a8e8d7413d33f84c5eed1a29ed38b13039803e18164076a86394c75f6fac62f49466653dbffabaac638e7b26158ff6c68e7f4be532aa04b365224038dc1a5d095babf111537b7ffe69dde9ecf08e0961f7133564f30146128683dab4cea1de52334f7fed4d01711700be34a09010200000000a370c8f505aad79664fbb008b27087a8e17bcffe8b7cdeab8fb69e19ce4b5ccc0095a32d9c0dc20017f3c71abb18d92db850041366731e71ee4b4a5665331458680200000000008dbe1d23a2fd1a9d2c189b52615e684920b6d30e2b1072cf0fa396502fc9aaec0768871336b49f2dbb90bf343cf020f32302c34c19d2bbee38f02b2cea300606010027fd72c8570620578263bdcb3f95434887b914315d776008b136dfed41f6ac77a635554823a7b5e9269fefbe982d67562efe7c471476b687d28d59590f656f03".as_bytes(); + + app.get_spend_randomness().await.unwrap(); + app.get_spend_randomness().await.unwrap(); + app.get_output_randomness().await.unwrap(); + app.sign_masp(&path, blob_hex_string).await.unwrap(); - assert_eq!(signature_ok, true); + let spendsig = app.get_spend_signature().await.unwrap(); + assert_eq!(32, spendsig.rbar.len()); // Replace field_name with the actual field to check + assert_eq!(32, spendsig.sbar.len()); // Replace field_name with the actual field to check } From 90df39e6063d7b69f12e1c1f907fb01ff06f13cf Mon Sep 17 00:00:00 2001 From: Carlos Medeiros Date: Thu, 1 Aug 2024 16:03:50 +0100 Subject: [PATCH 2/2] bump version & update snapshots --- app/Makefile.version | 2 +- tests_zemu/snapshots/fl-mainmenu/00004.png | Bin 9067 -> 8906 bytes tests_zemu/snapshots/s-mainmenu/00004.png | Bin 437 -> 431 bytes tests_zemu/snapshots/s-mainmenu/00010.png | Bin 437 -> 431 bytes tests_zemu/snapshots/sp-mainmenu/00004.png | Bin 366 -> 368 bytes tests_zemu/snapshots/sp-mainmenu/00010.png | Bin 366 -> 368 bytes tests_zemu/snapshots/st-mainmenu/00004.png | Bin 10924 -> 10793 bytes tests_zemu/snapshots/x-mainmenu/00004.png | Bin 366 -> 368 bytes tests_zemu/snapshots/x-mainmenu/00010.png | Bin 366 -> 368 bytes 9 files changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Makefile.version b/app/Makefile.version index e5b571ac..87c91121 100644 --- a/app/Makefile.version +++ b/app/Makefile.version @@ -3,4 +3,4 @@ APPVERSION_M=0 # This is the `spec_version` field of `Runtime` APPVERSION_N=0 # This is the patch version of this release -APPVERSION_P=26 +APPVERSION_P=27 diff --git a/tests_zemu/snapshots/fl-mainmenu/00004.png b/tests_zemu/snapshots/fl-mainmenu/00004.png index b60dc8efa96ab5e4339adfdf3fa2e100fe02ac52..2cd00de107fc436e58b474b86dd17ebe16852a2c 100644 GIT binary patch literal 8906 zcmeHtXHb({+wMbAK$=_Jiu5fgplm@v>1`_@YH$NaL%$aY_oSFB1&yVx`$;`?s_kFLmu614a zTFHOfT8rfonVFRrTH>Y_ zFcJKhg~NoU`4i)QyS@8U{F}M({)C50zg-Y6R9soS(NF~pT)SV-qIbPfuzc0%9W?*F z43|=RA^kib@NffHE(8E`*2R40YW(8BAHVnj`%}yX;{Ftr0UjPD0!jzt_W~utx`43d zKeH|Og@dN2Gmb`4R<`M6b=pd{_oQ*V?yJ@)CWD%(`W2F{E?b@TjLX^gLAVyV;~BehzX&={M^=)bWm; zhgK2?Tux=H*lcBX+>J3UVjk@WPldcoRZxk! zeG>o7NdQtnEhvzEK~NGtmHh-e`e$)Jjr}?G&VIp&j|}s}mIK`MQnf8Z@-cY8;5cz3 zboF+=xmn$>w>x6uQGJT|Ex~Dh(*oO7-1rmmJ>xxB=j!Kq?$NP2V&^b*@;=y)DmLjV zZ$)3>Bod0(UMK0nS5^yNsC+^9P|rm0!&%qj?&|ExGmPC^@j0TCVKPE7FY5QkTv=dH z#zl0vIT6K~_E6}`DHa1qe%k05PC{vdCeD}eV5-Empgr$=Qy)BBwX@*4E>*D}cf@x^ z{fMIIJ~hn%W1bJcZY`bI9OO(gcv9}`cgi$?JW_P?LV5?qpdq^--Qz-@3KzWLr>75i#a7<#ng-G^VK6LZ3-b%X3m)P@*kI7WAZ1oPtYv1?woMegeAsBYi8CB!2 zqf@N8`FPte&ub2PWqAn|ebSh-oX|9WZcj%4OOw}OtFn$CzP1k)%x@%j%l&c(kSI%e|wgSlp!^V3$ zn)EJ7Au0fL8bi@Ywu(Kw;}?MR&2p%!p}X*0KVp%M0$3`Gc{JP8KzDo(&LXDregF5{ zHPaXyrjz&@2lW_f%F-mmEY z9QVq-D7o{|qu`FMA*=1HDZFI5##!Cp{dd-G*GSjbjFmOuP7R?M3Ny|rEWsP(4OFHuKRaWu^C;I`*ODD>&&hF!mv z;lEm*zW06M5_2s&6rrn^xDDl8HJ46g7cDH|Q7bFQE%r}@>&!(r@vmoz)t3$cS^;0o zWU6xLK%ASX(2W5fK)NobIFsblw;%)@Qz3Tyg%#554*qT;2V5^KCO`FZLa{V49CN^2 zP(7L`6TTNXcdeKY*!!=-%KtqmFQnO5Y7okk_<#_e-Nj=dhG_x7DU?3&?}qmOVy^0I z5Esei)_mV0H`oi}Va_DoryC^wRO>@Qrx9T1F`qvhB$DYNT3xr=%=Q2m2EfI&?)kFq7fdi`e0V?=*>#PrD`%adfs#g zTnL^lGVmo|tJM)}R}%gtbjZ?fzu-1M?3h>X^AAYR9_7ssYAHPrfF(0ayIZcT7*pi$ zDBlImKMy`~QtD?@_G~@0vT-_%@f?RYdvD8!R1WT2$bT(V*|#x4RfsblTQFdfGo$VSU#;GRN*| z5@HUzy(aOEl&49IDnyDwp);w|wfd(W@O;p*rp|Jtsdmv66p z^T-m2J4?svC)Qkld!;$V_Jx+WDW`DUtzUBVaK_pxBKKQF%Oo=bTPyFT$trs3WA?Sh zYvSj^?L-wcy_tu=-KcJB zYr9r8+;JTlxKbGIZALLVu>(Cv=UYPd%J^{4dxYMo-}qyNdBYZ$G~sMixEWW-z73uc zBgkH_t(jH%0@z`#v`|T7KoU9s$FJb})F~;cy}qn@;_V|hp9tUJLfJ?XNJIMBtr`Sy zMKm`?<`d8p0cVwwI%P5otlk6xJS0?Tye7mcYc(jC<=c5YWVN+J>X?oDwVPQp5iP^# zzIw>!MQN2SH21k)Hk;EB0oL-kiM&+}YiH8xmK95({&fZ1pkW|>NW?s=iKk~b!@*HWv%sLR+V)oXoC2P8{af5bClx^Gx{D#a7PXydq0URgOLns zsv7P#y>WjqsOe@c2`qIj;T_RJv;C*}Q-NK%Q`r^SfPf@6HvB zTFS6rd4?Z(mCH4nkfcuQ(Suuf`i2 z*1DM|-GOgGp)Rl7^|=H$=~PX#d+dEHEYF9en@xIO8T3B56sz+zf_QIB;V24)j1aVii8nmV>oNf;&hMr|Lqkuampg96`>>comc8}F*f zZHxZjL6ZG>96ZclFJTouV6^dI6JWw0h0zDu`!9@wC}Q#up$FI4T$5?V_`lit=w4MIxkXLLaK$LWZc0tJ8;46MJ;<*#0|w@$5| zFNI7n;fv$n^+$yEMi&idDw>^m1=50uB0l2*x%d&<4Yl%Jn6&Cw$vNhIll+c{sCCrV z<#RVuNK2XY2KsfZi+cqZd*Kvy2W-DHc|DPn(V1c5zT1BCO*Slzal^EZv@y}Jajh!T z{zU4u`rshLRN%hhV&_0G$cYGDy-~f&qwu{;`!IW9ckHj5g_9O(p(HPG6K(4Mm=DWC z9{~Gm{U{fI_C=@ii;tVH)#IZV$79IMYozy;Cu}J|U9kaw;2#F}+|dZXA02-kuI_z1 z8MLw(Vs{W5>HhOASL~amSKfEx+rem58_JjSvZLdrX=LChkbO1uvSYfV!gu|s)paNi zXK{E_Ti(6pWT_XM6AihJxi1z_uF%ir4*(aR#+I@9-if=)(L~bEg?}bj}@RHC*M*|dEu9!BxZrtNKB>)kM zoA=_iE1ql8+m}!r*)`H5%duK=@<(bLO&u=UwdU-atCzOX`$ViLL(}-cgm*Rbt$A9^ zJpk_z15&r;zaFVBG}{(!E#Y%RYF%Uj;kS6#m1}E7?x$(vfVuEuC*QwQs{Su~^Wtl? zMz+FU0Ka0bo~iQXYdZkE%lQucYh?5PWXpde;kSD*xoC}OMacxElu{+(*(0B%L=CHtiwYuGP;zlDMovV~>e# zhv;jV_5AgE360xKc(HclzftlzY z;RkTN6Y;6j>jCdwYM~%f1snpk8w?=@Al~On97ugUt)Dv0jPRFe32Y*ls=*Ei<)H$} zHFVBEC#Bs9GB~ICQHx=+rQe3nfLtDGtR5TrT-no+YT$B%6i#m3e2%o9T9gkVg>N3S z*xzw?D?_;+_Q>yBof}xBRwH2TBQ@oVt8}7du)8sFx~dx;a0hyhi$j#LWa`*h zt|+pWC0_49D+$)IIlvzJjL%oxw?q)xSC1|7EW&xx&J{g#JZM=+iwI&&);uSY&(vRG zv_wiN$2U6uDrk}AX=w)@pF870Y27ZFN6hn3zIlcw4Y5`4BJqxzb2jPVpOJ&cro0MY zNqvI0>d0zptI2IzyVqP2zxkiVNr!X>l1o23QH*Eqc&h0|6|Su=QXqc`jz82F=8u-j zCUhbyBca_!n9=P?Dq?}cM^;4mt+#)Q?ShRFjLiPzdf=n{=Az{`OMqv;`bZtdjww$!h3_vbpe14eQ-kBMG{bR4omF+_D&$g+WM^AM z*xY^PC4X>Q9Io$txZ5}L`|%G5(fs|!ts+Hm?O+!F?DD+qiqO&vKC0ZPGmH>qHYbK} zWzV*M-3m)rnc{fk-)=oRkqCd@BoZc_I7|9bQstPR?PHV9Sc_g+JG`JJ1}SDL2b+yO z?0@6;szguJ)K-DF_6hST)x73iC5u0=^vEG_2 zcp}4jN0RO&FCaEsXzqh=Y+HB4_2-EUH-I|mw>ehu0?eypjyonU4=+=>+5H9c_4o1sNlCx9%D zsfv`ok!gRCg(EYpVbNj63I*`5je!sr10%mEUuRO~(cdX)qHV_lV6jr#uvoP|mM*aE zy*iwDF#~}*GZ7f;kO>c5#vS5Z<_?+1_G8w+#%1F@ zoxHjTuU}3vK8QQpY~hbHX3EsG`&VnaH}<2Wf8+~Q z{Ww4?3jWyEo@nBK7wghb3uWDDG6Qx>&#OlH=1GWibLtr#x4_(&}wV0#_$!&E&a@b!I`>OoOBe!nc)0ewkfJ7aM8kQ6au+@(GF8eC& zknNT%no6b4ZVzBFUxAGLK?aKZMV>>WcC=SD(`!AcEtxcw6VmiHn0I&JspwK@zS-h#!ezv)$iVo{e{~PHSmM@bU z1D#23(kU{T*Rsm(Pl&avr7XhT$RIyXbbIBhkT~W4N%))ftT32v0Cib+x=s4yi*C*& zGV`o(0$~Qs^==P@7ermECDA(^!P94YdCp9sYk4X}X)sPVRM1d30lC9&3arY`cQaPR zF9tYe*`)uaNo{1pup_}}a9bGByH+D-3fiyy&HW|>{Mo>g9GJA9@C0vXhWlx3Vq z`D3SQ?95`rSOA9~3iWiFHAbq~K%vb8WacXL!QK#@0ZQL0=lzf_q|3XA+&FwJrBp4Y zwB*Y(ly7s5j%ZF6#DM5XYLFP~C`)iA{O+45&b8o(&rWf6#*ox?;a^}OnUXhnbk_{fjajH0Xz*EgH zEK3CLGWkin|w+i zK$WjrQ|@b6|JUm@3@+fnJgHZX1MU5S8&Kf_JO?cmrE#qH0Dk=!; z{_!bX$*PgE`Pb$5n>ZFyo?HT%OScu_%-nljd69K^4PiXmvL(qHmgw~oGYO)UQUof` zsfJG&od7h^_$cD$ottn!(r5QgPQ!C{e^0=tbtk;Cm2KRhRZTzudG)?=&{^cL-wOCq zV|S`a{@9Nt0}HyW2&3|=S)OYyH>$7bUcI=X`fN@z9j#Hom$PiPb%^geaUve^-BaBR zcPi#(g)-8I9MNzC9vcg$>(CnEx+_PNrYm&l21j=2$s8^!V?5xj>yGx?Oh{0J+owTU zA8+@rt!{qv$4&w!Jak5~KX*zd=y+SCRMqfBYXbrr%nn@coVoY5Hh0m}wW4CJjOES` zCuzejI4mCbsd@K4@;2adXTU8Y)1>2phZHPA31-0&LxXGv+p&eF!F^akw0Cq%i%c>lFm^-6OqAIrdn*xJO_66Wv#maAz3hwA z{VGuHx|qKqEBJw^$(0n`9FJ@_o_tp#BEGX235zl#DrcAHEOT6<<}}aFG%r0Tw1I#+ zANKP~;ee_S^_EWD1{^z}Xo%h!nx~J{X5`)9SL}rNu|1@n+j2F@ZQVs#2$31NPZ!ua zLD>0n5-`{N_g+Z;Ls@~c4w^Odx2)S%D^FK(f=L6wVK5W)ue%)mhb{l?TiE|U(0`+$ z|F83Yu^INBPNz)7fH-=Z{Rx}&zwc;H|38t$Sc+e0c7X}sI|IRR_M?sx@fBnLcSa3`W68`6`BjFhecm6Xr7r*^cWXH*}4@z#?ITcICicdMN*D6+g)CZfB9c*PD)4g~w4h=n8e9L{;SspIEbwehkl_71IB_}GEl2j*9Sg`U_G`n%kD8e z37VxY!_#o5zY*45YV+ar+tlnY zrW=RmS~{{{(jKF3AvLzJ=$vUlm6zNqVCf3 zJXA^FIm%qGo21OTIqN{NW$OU)+&}p_#{Vf0Y%8AB`{};E<@yo#!kyf|8Ib?Hh|mh?xLxECxYxmMNo2>~85_pOrj(;~Ox z{5IhB2B}F502I%bZ?icjBnkYs#~;|8X(OEahsb{5_MrjbfGkoJcqDEBh}-^~O&-+R zxI&xOb^|s$Pb2N~ZnTc8N~Jf62?2-B?}*AfQZs0Gyot_Ywp>p%0iIj!K^jH7T=0d- zi*&Y3Z3A`)YAu16lzDu|F;+f@JXmrNuCs z{cL8!Hxr}7?;C^O{^cpf?)qsF>a91pq${DIM9b^t?Y8|m=F_QhH8L|TnZX%~9#0{8 zB+7QAUp+bSd1G8fN=%9&q|;ED9z2eHA0Vu;=adAguw&;H8E0323-RuT&J8k*4#W-R1#reViM7MadjNQN1TK zD@G8ys3Z@&w^JS4CS#S=*Rxt5h^Y z(rWcbb$xp><5=b=gGJVUb0jfVv*X1bAxN2Zn)8iT?=@AXXE~}`kN23eR9B{p&kYc} zavWMPJ^7O&XdU-YgvJJQBVLW5RB83GLdh(bR8)bj9lL%@qRXi!Oj!=ur&Un z-Daz3!mY`5Q*`-hL94>Kl4`%02ogPV=!IrV+WO^-n75tR$Z*Y` z2>hsomE7G&R`*8;i!rT3KiM) z*seCRQ`f7EcUqsi+}Wt5gqk(M^xLl{(RF$vkor1mBj6e5_lWm2mKNRg0H->~{lHH8 z_GYNiOj&AX(?3Ll|7`XtK<5-%4}C>Km`sR8e=F1P*H+J7)gQ<_E8Nj+xaD8#jS~jC z>y-U%E4O*R;UZny&qlgf1IG>`U0f>hTDxv}E`9|%xFX{r1`y|DMDahcX*6y4i9Vp% z2!f~X-vN{V0*?_7oNOIyEhT_dX0FqT%!;P;Z9tgb+im|zRR4dLYk3h04W{8NcLJmy zjB98)v!w;sN4o1}(hx=?RHqSHJmS_^XWu~dxF7yw<%yn%giYYb86D{tjCk7O@FsIL zq0G(1E)R=cq58ruh)20oXY{9{%)qFX1@q24oa4i8nhW)yM$f?LoI8&P1owBJIs%a1 z>_z5Oyi0PIeLLbE(>nclfWxm2$RYc{3f43vfwnPMG$Y2w<2#Q>yCi$BFCysW)xp{7 zfFr%3Ku6|vE3vveUU6n+D^w^{a_In#t>hCutpD1b8jn^G=^XL)gZllRz~mR_6M|RG zlIa|a&;-xZyW`MQ51aZoTKal%_f)z+= z4>-8(7GbdCy|4Ph3VZ_uh7f1G8>}D=@}e+&IL1O1o`c=OjWJCz{g6Qu9p%mIz^31> z?c9X+G2TNye9@g+9Z(7%G*A)5IbK+`@+o~R)lC&x%z`I2D42cDP=(vzx=M-#NW&3G zN@MShCt4R{l@WKmW-WZlpE-Q3o}U)|jlJ5$aYOSvYd5=e4el7~%b^**uox>$PvZ;5 zx4!F}Zsm)PARtx;pcx?YMjlv8q^Uu7i-aq4IF*=nv~XNt&-MiG0-uDGuG`IOI_%4` zwrNUE?Utj=)te3pCTemmAJL3rxt#4|_M6iYdbu9j3cRNcj-$`aF#T)JFDK3eq_+`B zVora=2wN#;0k=hH-C~mXwebV?UI@gO_@TZ~gzms#pkmVSb%(9|ZYyLiObQsQ;CxeT z^?qwL_u3Tlx^zP~?q<5BwWr4)R?QugX?A%F99}2Y{&^t_^Vr||RP&7B;=;jb_gJbY zkc1r)3dXrL=(x{$?C_?bLuhNy7(8Ap>2dInd&YDQ}Vh{!^@kD(adpa@Dq}tc}@0CJIy@qO2dv)OP%F2j!d}Xbz?`eJ?I!YK}DwN-Y37$S@j_ED zkIz@J{mUNiD63vS=<06%$-t0DLG`KU__$xSR7;MuxB@FkxSVh_;c_r-EOB~GP7ers zc~s}JUMb&~&Z#NHG{@iJa!$Qw*3py#)}k57`mDEl$paBwse_cb1!#EB5n#*=VK6*u z-5#GPFv;m>uqRhl$W!5F57IsvsI;NncZ+a`l_OpD+Byyzq$yw}tfYWg*z8@t!(*0M z-GfiDVShY@Ax)Qg_nP%I-w4B6~rfuh+ST(y~b)R z8Fm~>ZJK!Ka=~4@FlBk$q*T`8X;dzfy%A&`GRCkVj*Mv+W~JCElPS&#!Dz;+2ehCn zuxWiKO=HWUKBK?MTv`Yv4p>KuNI= zkV?Em`35rlb75gKr!|~(@S9^;tkZ?;KK5+cEFrk8aQ5lFPSaVFoYlwa>=Qt9&u_?K zQzevwQ7&r7m!s5ze;^nI<~F#BDVnjufCnXh#_j;1>;K4x*?yVMAIl&R5W zN5Egqdei`Taz|$sZKAV|biNB368rorAMET33raAv%WJ_+nHUvT89*vIOotj7-bWzi z&%|&ETF6W8&t;4LvYKAi7dZBEoB>9R$ino)$Ngg}wrvhnAkjs#!yuz#@V+#S5@>Z+ zQt?(8vHC3|4{5X?90&E%*x%uxwZ~r{W}$by7E_Y{nSra*vD@p;Xw=fEel@fn5CdYj zCP_^Z0Q@hCjNOhnIXAI0BQY3kV;G$ z5qccBbag2trUk}NR4g`Es|pxHKtUD5sY+ZLyHq9?n)2B=T)2%%=N-$QRs#I4Xbt`OqGXg1&N?*Pjp8Lv8OZqm}Yp39)Xf)L=>WL8xrZhO`3dR9ISDv4BLZ-%2VritL zD?H5{+kb^tnr~U1MK_LgPzKbs_Rl_R$`2fA?cm?hxW%h&vQ(aBu3jmqiad5oT&Nno z&EjnZ;^&9i7JCeK^MU>lx|M*D=-?y^dgW5#FpU8q71gXD_V1U={{)BsMwbhYRb^JV zC4yT=RjUG{a-g&@FzF5A*x#$}|C{A<@x6YT6^cn;*lh>IE&8weDLO=flndNHE|Ik4 znS#S&am)u!r+0tZjOl&-3-q49Sx==O|3#-Dxt+gAjJ#qu-T>kw3JO4~Dn+I!R3o!u zV;4ERtz#tB4VhT8B3&>-cD<9u>cELcws*^-l zv)D9g?&U4X7>JeZAW+h5vC|HKN+&j06C{MG6L%1vGRD$-bLy~L zA?D9+mUJJlW$}DrQbZrNn8o@cZOV9y+j06gp27i3PX?{+n)Vn}4Kw*#A+!$k*a+o-|kE-fpw#$7|sueONJ&+Y`7)$=>vKRFU|L_7nZ=PX>K# z3y3q18k2Z=4ciNRGs&46nS08=`nFw|xOPj`*0H2I#<*{ajVM`59W;pc4raZh3CCCk zb*CHyM7Adc>B*EG5HFqXbGCQsj>z{N^<*uLzd2J5`O~r=Zyf&W+Cq(}YgGbVo<`z< zGSS?V*X59n7+Ik=oL>7$k^U@D3`6hdsgl9bZfqZW^H$4`6~7ACScET<`*I$!HSxs_ zO|5Gk>fJ(?4Q#8m+IDQG#}8h=m98hRQ&8FqqG$hv(rk*;VtX8Kxk2s2NR1Y-M*(~3 zd4Kb)!=thEcfENRj^owfm~)T%uZPLU#mNj-LN7>CR4>)v46~vxoMAc}sw(~1M2`FZ zIC8%sbWm`%*Hme3LrGd%c>QvtP_V$maEpdIH%8#kZwLfSBo}_7J?hoZx24@Rg5XXc zRFP@Qxh-C!B-#;f{Y04Gk-FHoN?!XB5S(^SWifXj??DW&`shr$w}-h|OxvFICXwx9 z$Ah*y11Qrc)jRp}CI`VKC9l12OWRdMW`w@5PQ^&9&vY!Ea*N@eh66KY#%cvKH8Qq) zYOIBGRzZTbkktk$Po^7_)N|e2zqOsos+bKkc|s!n!6SwW1*^sL-m7zavEBO<@RNg4 zuTxGbtZ^&CAt zFn&DqwNwQjoo@UQ?lKfzCUu`*n=%0VWMrZjj0l-?wbb=YjO0#zNLgzzdxp?BCaM-S zv5lAR1bxWYLW*+FTnc{?+&UW6OBzdTp4qy}3&VVj9-oUkMcrrKn~+&iG~x`dvD>BU z!6zQei1$~gDoAzV7?9`=n)8Cv6UBo1=SL!!eR6vZOj0}Px9@eTWwOmBQ@3CO1M|q5 z$BkNSi&&>2Yw7+8uPDk16w#^{UPd>IP*(^To?(D@@;%4C8dVm%shB z)@#~pI9zhV7hzUL`@;rj;URv_sHyOC>m8yjdCRSIA)7anyu~dVk1;eB;Ed2gUL5?K zQ|N5hHJYZ>nzxRGjP!_|_C%{(d&oX`gY(W*`U>Jv=mA5$pJJjxn1xz_eXdEQ`aH$P zLBcKDBl;6*^j+UcAyR(1jl*WVl!kUrM)ip6(^b@JKE%Y;KG%KYlX3FZ+)n2{ZtMHp zb`2kPn=fo4y6Mk&uaasXyo`@=T+3R@u}zq~XYU8(Fj*L{)f%78+DKaB92LJcM=~)C z&tUf(d(pkR&`r(P>mh>@_Awl>0n)LLcGs23K3yr3mf=g}8zB!lVdeGh{a9Uzni{Po z?jwLS>WYweGl@Js&J0oBd;=+Bzwf3z3#1KSyAolc3Mpf@pyP(5#e(cl#eY+Jk}FTy zRBEKt=`(_lY4}gTgVMo;8Qy!9l|uTPu4gUGdS80$Lq;_WW$npkh|4lUf&2-bfjDPw z=0V==Sle=>oyh)Oqbv@^Lxj?JucsBcvyn7g4KY0Kqz!#Ct z3jx^&#H$sE*R*GZPxYK)jDiUYyf2Ix^bS}e2u{DQIJOdn#T^X6GFxzgRhQ8Wu16nk zxqLjNM&Ve`DTp&;^jPMH#?RUIdEcRFqG6)FQbi9^HJ_VpbG6EQu^4>w@dq(3X(rDQnG zCs~>6=$YR`Ge*H*yPVAsX$jcx9BFwZQN~f$lu13#a-9g8ZZL)*tPCOgYssde@7%9$ zJJ5L(X{3RB8*V|k_cRwz3fenbk20MAD;4~`cnzk=%FGm>P$F-R(Ntfdkh`ZNK2|nq z2B?4GVe|&0mKH;=<<@LeV^E2Zxx@f>5L-z;0_ zUkvpItrW7TA1=x? z+1Zg*yL;9&Uy1sc;;1N7UvGMB3ycOMIl;dbM%kC^6kY^%J}K_UROiGrBCb9r$jE0Q zoGmY@`iF}7)2Ru^ZE=6eQPPGrX!Fjk>hgm%^^j78pPznpzYtnCT&UD2+}DRjs2L1+ zNeebYfkJCbzzc01pO?$YcBzRc(KV|+8MJdg-At}{($WRef^&0Wf>}L&0WAjdC8T{9w$HCVtQb6@p>mD$Vf?L+5iIjS6>dSz7YKq?kAU_ zCvu5dJ67C#W)JqgLY2SzHZy?)Kh0LyGBV=#!75$q*lKZ&YDng*u^%()_Xg)4KN~m5 zCK`p#3_rtuTKz1eV(Zx3w*A?@4An~ozKnwjP5d6>Dz0VUnn*hbQoil9y!m+(Mz17! zMVtp0@nBh;_czjuIf>D3PQD+;6}gv@c6-g4ool&2jb8gZLWjZ$Au{JKiu5_0d)@=1_jbr+HhE6m_s;+o`5R>etdP%9~Bp>z( zCGLCGp|n$oH2NFTXmKE)AhY0F9Qb3UOs{t;9_`>^XJS1tvtSIDnNd}+&*}R~c~4n; zoSi@3nHX~EOJ!yM!h}7h7;f~L6f)4e&Ld(NuZoSW!PMW^3--4}&wv=Fe$#lBGuiw8 z?L2GIWP#_o;=pP*9-tyIeW8!ogeK~ovmWqK(99XHtPG`W-fgezRAJAt z&nD4pD5(aYgzG$(N;jDC6C*l2X%VhjRF}ngbHk2o!8mK>C*Q{5T7h@Be%!PdqQR7U z$Kl#qa{KjuM&#D_eaW}h`V58LCa6mMM~8V1WyBEvg{Q?eK*_YmlEcaTR~MUDJeFa^ zq-%VQjc`YOqX5$;1W5d?1=4>Zq5ci6?BIiHeUR`{R5*Z)kis zF0m12Wtwf3{`h5f(vboG>x;jTWSiRj<~466a17($%REl|{pxA|gv}HW0w7 zXy*qXoFzSY0ZRcVk=f5T`!ruGZtx?zyt@&adDc2>#7q-3 z)Y;FE%wzsC9QI#v5U>Ab*jo89_b(4PNT;Q3Dp{-Y(JmtU*Ch-Rh_O$9y(X7`jBIl( zlLP&dF*w_T1N~wEg|`2rHte(9bXw9SL z5JD&s004lia!Z=$_54ow`2V?lKWMIl2LCmGXWzipxo1!KdbYmFi-QWcU7E2kiwmgf z(p)zNABh20!0qw*P;D=ks@F{HB1Rr<@L|YZ0gEp;hS*>i+kew{4xWoofaqiR7klZp z&RP6jHVmFldI&lw5DyvOJ)FGT<^{XH!9 z?7a3~wdngC&3|gG#^0clTcaAk!V5YfhJ=xDpHDC#6ipIr;u&uHEdBujwMtKij5LaW40 zNY+bvlJZ4TvP`Xx-#5@?m?ZuH00000T$VS`+Q>SLIO6#;hu3J&~vNr5 ziip#TzT)2p40WIjlxlEog?S$2oiux5HdRBjt-4Ynx|FZtvvPDTXg}Gk!AXHte(9bXw9SL z5JD&s004lia!Z=$_54ow`2V?lKWMIl2LCmGXWzipxo1!KdbYmFi-QWcU7E2kiwmgf z(p)zNABh20!0qw*P;D=ks@F{HB1Rr<@L|YZ0gEp;hS*>i+kew{4xWoofaqiR7klZp z&RP6jHVmFldI&lw5DyvOJ)FGT<^{XH!9 z?7a3~wdngC&3|gG#^0clTcaAk!V5YfhJ=xDpHDC#6ipIr;u&uHEdBujwMtKij5LaW40 zNY+bvlJZ4TvP`Xx-#5@?m?ZuH00000T$VS`+Q>SLIO6#;hu3J&~vNr5 ziip#TzT)2p40WIjlxlEog?S$2oiux5HdRBjt-4Ynx|FZtvvPDTXg}Gk!AX^xgA+;tp@|Ej_A@L8fZS|Dz+PzEEip z3uah`qDS@B`) z0hgEDwC8xI^o}Fq-lg<}!EPJ^|(W1z(=32}*x5diT=0S(?*|DQo-O z`SQgXZoiJHt8FVhfk?L}Ys7O)r|^E4TlFs+J#e0c-b{z3mh>zP>7gbwY|~RuOyq hq;G0m2>&zuJ0+Yx<)Ti;iiBE_sHdx+%Q~loCIA)on3@0p delta 339 zcmeys^p0tQO1-J4i(^Q|oVPa}g_;$390G5>^xg4);tp@|kYjERA_gn}=BI`(n#|yL z(2@ZG430W~|ESnf@nEmN{o{{I(tWw=ZUz5l{dd>;f!$D;gY2OoyrHM=+MS5X;5 zr`n?$)g4^Bl@I9ODc={ga+~RCvy!j8|9c+0&WnN*cIE#5 zbK%|-mk*U|L=uAZbe8P!6FYF?hR^2W-@m8KnzHYFdsF|W&o0V0_is;{bn;)S(Mq-7 z;)~g4&1g0GD0^*-@A^+!8QrI}(q2xAP+m3X2;asfmn&Xgu-&!hk8s&+nVG&fBigt& z#KqlPSMrU!dt;)HwWQX8f<;|!VfR~ZizOVBn04?-ox`SkZ(ntO*1ox2W4Ez#*^x5+ h)~Q}82=6l#B^xgA+;tp@|Ej_A@L8fZS|Dz+PzEEip z3uah`qDS@B`) z0hgEDwC8xI^o}Fq-lg<}!EPJ^|(W1z(=32}*x5diT=0S(?*|DQo-O z`SQgXZoiJHt8FVhfk?L}Ys7O)r|^E4TlFs+J#e0c-b{z3mh>zP>7gbwY|~RuOyq hq;G0m2>&zuJ0+Yx<)Ti;iiBE_sHdx+%Q~loCIA)on3@0p delta 339 zcmeys^p0tQO1-J4i(^Q|oVPa}g_;$390G5>^xg4);tp@|kYjERA_gn}=BI`(n#|yL z(2@ZG430W~|ESnf@nEmN{o{{I(tWw=ZUz5l{dd>;f!$D;gY2OoyrHM=+MS5X;5 zr`n?$)g4^Bl@I9ODc={ga+~RCvy!j8|9c+0&WnN*cIE#5 zbK%|-mk*U|L=uAZbe8P!6FYF?hR^2W-@m8KnzHYFdsF|W&o0V0_is;{bn;)S(Mq-7 z;)~g4&1g0GD0^*-@A^+!8QrI}(q2xAP+m3X2;asfmn&Xgu-&!hk8s&+nVG&fBigt& z#KqlPSMrU!dt;)HwWQX8f<;|!VfR~ZizOVBn04?-ox`SkZ(ntO*1ox2W4Ez#*^x5+ h)~Q}82=6l#B-l^>u2nd_yZP+A>xEUD%N93d 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 diff --git a/tests_zemu/snapshots/x-mainmenu/00004.png b/tests_zemu/snapshots/x-mainmenu/00004.png index 170669861d84465d5b3b6d80c3bdb918f367a8bd..81c931a4170ed48609740263b1746517188e9e3b 100644 GIT binary patch delta 341 zcmaFI^nq!DO1-(Ki(^Q|oVPa}g_;$390G5>^xgA+;tp@|Ej_A@L8fZS|Dz+PzEEip z3uah`qDS@B`) z0hgEDwC8xI^o}Fq-lg<}!EPJ^|(W1z(=32}*x5diT=0S(?*|DQo-O z`SQgXZoiJHt8FVhfk?L}Ys7O)r|^E4TlFs+J#e0c-b{z3mh>zP>7gbwY|~RuOyq hq;G0m2>&zuJ0+Yx<)Ti;iiBE_sHdx+%Q~loCIA)on3@0p delta 339 zcmeys^p0tQO1-J4i(^Q|oVPa}g_;$390G5>^xg4);tp@|kYjERA_gn}=BI`(n#|yL z(2@ZG430W~|ESnf@nEmN{o{{I(tWw=ZUz5l{dd>;f!$D;gY2OoyrHM=+MS5X;5 zr`n?$)g4^Bl@I9ODc={ga+~RCvy!j8|9c+0&WnN*cIE#5 zbK%|-mk*U|L=uAZbe8P!6FYF?hR^2W-@m8KnzHYFdsF|W&o0V0_is;{bn;)S(Mq-7 z;)~g4&1g0GD0^*-@A^+!8QrI}(q2xAP+m3X2;asfmn&Xgu-&!hk8s&+nVG&fBigt& z#KqlPSMrU!dt;)HwWQX8f<;|!VfR~ZizOVBn04?-ox`SkZ(ntO*1ox2W4Ez#*^x5+ h)~Q}82=6l#B^xgA+;tp@|Ej_A@L8fZS|Dz+PzEEip z3uah`qDS@B`) z0hgEDwC8xI^o}Fq-lg<}!EPJ^|(W1z(=32}*x5diT=0S(?*|DQo-O z`SQgXZoiJHt8FVhfk?L}Ys7O)r|^E4TlFs+J#e0c-b{z3mh>zP>7gbwY|~RuOyq hq;G0m2>&zuJ0+Yx<)Ti;iiBE_sHdx+%Q~loCIA)on3@0p delta 339 zcmeys^p0tQO1-J4i(^Q|oVPa}g_;$390G5>^xg4);tp@|kYjERA_gn}=BI`(n#|yL z(2@ZG430W~|ESnf@nEmN{o{{I(tWw=ZUz5l{dd>;f!$D;gY2OoyrHM=+MS5X;5 zr`n?$)g4^Bl@I9ODc={ga+~RCvy!j8|9c+0&WnN*cIE#5 zbK%|-mk*U|L=uAZbe8P!6FYF?hR^2W-@m8KnzHYFdsF|W&o0V0_is;{bn;)S(Mq-7 z;)~g4&1g0GD0^*-@A^+!8QrI}(q2xAP+m3X2;asfmn&Xgu-&!hk8s&+nVG&fBigt& z#KqlPSMrU!dt;)HwWQX8f<;|!VfR~ZizOVBn04?-ox`SkZ(ntO*1ox2W4Ez#*^x5+ h)~Q}82=6l#B