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/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 } diff --git a/tests_zemu/snapshots/fl-mainmenu/00004.png b/tests_zemu/snapshots/fl-mainmenu/00004.png index b60dc8ef..2cd00de1 100644 Binary files a/tests_zemu/snapshots/fl-mainmenu/00004.png and b/tests_zemu/snapshots/fl-mainmenu/00004.png differ diff --git a/tests_zemu/snapshots/s-mainmenu/00004.png b/tests_zemu/snapshots/s-mainmenu/00004.png index be974ce1..6a648e29 100644 Binary files a/tests_zemu/snapshots/s-mainmenu/00004.png and b/tests_zemu/snapshots/s-mainmenu/00004.png differ diff --git a/tests_zemu/snapshots/s-mainmenu/00010.png b/tests_zemu/snapshots/s-mainmenu/00010.png index be974ce1..6a648e29 100644 Binary files a/tests_zemu/snapshots/s-mainmenu/00010.png and b/tests_zemu/snapshots/s-mainmenu/00010.png differ diff --git a/tests_zemu/snapshots/sp-mainmenu/00004.png b/tests_zemu/snapshots/sp-mainmenu/00004.png index 17066986..81c931a4 100644 Binary files a/tests_zemu/snapshots/sp-mainmenu/00004.png and b/tests_zemu/snapshots/sp-mainmenu/00004.png differ diff --git a/tests_zemu/snapshots/sp-mainmenu/00010.png b/tests_zemu/snapshots/sp-mainmenu/00010.png index 17066986..81c931a4 100644 Binary files a/tests_zemu/snapshots/sp-mainmenu/00010.png and b/tests_zemu/snapshots/sp-mainmenu/00010.png differ diff --git a/tests_zemu/snapshots/st-mainmenu/00004.png b/tests_zemu/snapshots/st-mainmenu/00004.png index aed453c4..7b1c3a7e 100644 Binary files a/tests_zemu/snapshots/st-mainmenu/00004.png and b/tests_zemu/snapshots/st-mainmenu/00004.png differ diff --git a/tests_zemu/snapshots/x-mainmenu/00004.png b/tests_zemu/snapshots/x-mainmenu/00004.png index 17066986..81c931a4 100644 Binary files a/tests_zemu/snapshots/x-mainmenu/00004.png and b/tests_zemu/snapshots/x-mainmenu/00004.png differ diff --git a/tests_zemu/snapshots/x-mainmenu/00010.png b/tests_zemu/snapshots/x-mainmenu/00010.png index 17066986..81c931a4 100644 Binary files a/tests_zemu/snapshots/x-mainmenu/00010.png and b/tests_zemu/snapshots/x-mainmenu/00010.png differ