From 5e6379af1e84eb1e8defaabd6144c624d4df6464 Mon Sep 17 00:00:00 2001 From: Ida Tucker Date: Fri, 14 Jul 2023 14:27:58 -0400 Subject: [PATCH] get shielded outputs info apdu. --- app/src/apdu_handler.c | 34 ++++++++++++++++++++++++++++++++++ app/src/coin.h | 2 +- app/src/crypto.c | 38 ++++++++++++++++++++++++++++++++++++++ app/src/crypto.h | 2 +- app/src/nvdata.c | 4 +--- app/src/nvdata.h | 2 ++ 6 files changed, 77 insertions(+), 5 deletions(-) diff --git a/app/src/apdu_handler.c b/app/src/apdu_handler.c index 4d4286c1..b6704018 100644 --- a/app/src/apdu_handler.c +++ b/app/src/apdu_handler.c @@ -197,6 +197,26 @@ __Z_INLINE void handleExtractSpendDataMASPTransfer(volatile uint32_t *tx, uint32 } +__Z_INLINE void handleExtractOutputDataMASPTransfer(volatile uint32_t *tx, uint32_t rx) { + zemu_log("----[handleExtractOutputData]\n"); + + *tx = 0; + if (rx != APDU_MIN_LENGTH || G_io_apdu_buffer[OFFSET_DATA_LEN] != 0) { + THROW(APDU_CODE_COMMAND_NOT_ALLOWED); + } + + uint16_t replyLen = 0; + zxerr_t err = crypto_extract_output_rnd(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2, &replyLen); + view_tx_state(); + if (err == zxerr_ok) { + *tx = replyLen; + THROW(APDU_CODE_OK); + } else { + *tx = 0; + THROW(APDU_CODE_DATA_INVALID); + } +} + // Get the sapling full viewing key fvk = (ak, nk, ovk, dk) __Z_INLINE void handleGetKeyFVK(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) { @@ -359,6 +379,20 @@ void handleApdu(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) { handleExtractSpendDataMASPTransfer(tx, rx); break; } + + // If there are any shielded outputs this is + // Step 3 in signing a MASP transaction: + // the clients requests information to build OutputDescriptions. + // In particular, the ledger should answer with + // rcv, rseed (after ZIP202) and optional Hash_Seed + // This APDU is called for each shielded output. + case INS_EXTRACT_OUTPUT: { + CHECK_PIN_VALIDATED() + handleExtractOutputDataMASPTransfer(tx, rx); + break; + } + + #if defined(APP_TESTING) case INS_TEST: { handleTest(flags, tx, rx); diff --git a/app/src/coin.h b/app/src/coin.h index a6139640..5b48f6bb 100644 --- a/app/src/coin.h +++ b/app/src/coin.h @@ -103,7 +103,7 @@ typedef enum { #define INS_INIT_MASP_TRANSFER 0xe0 #define INS_EXTRACT_SPEND 0xe1 - +#define INS_EXTRACT_OUTPUT 0xe2 #define INS_GET_IVK 0xf0 #define INS_GET_OVK 0xf1 diff --git a/app/src/crypto.c b/app/src/crypto.c index 3f87a2f0..aacdac0a 100644 --- a/app/src/crypto.c +++ b/app/src/crypto.c @@ -711,5 +711,43 @@ zxerr_t crypto_extract_spend_proof_key_and_rnd(uint8_t *buffer, uint16_t bufferL set_state(STATE_PROCESSED_SPEND_EXTRACTIONS); } + return zxerr_ok; +} + + +// handleExtractOutputDataMASPTransfer +zxerr_t crypto_extract_output_rnd(uint8_t *buffer, uint16_t bufferLen, uint16_t *replyLen){ + // First check that there a still items on the list of shielded outputs + // for which output data has not yet been extracted + if(!outputlist_more_to_extract()){ + return zxerr_unknown; + } + + // Ensure that the INS_EXTRACT_SPEND has been called + // and did not error. + if(get_state() != STATE_PROCESSED_SPEND_EXTRACTIONS){ + return zxerr_unknown; + } + + uint8_t *out = (uint8_t *) buffer; + MEMZERO(out, bufferLen); + + const output_item_t *next = outputlist_extract_next(); + if (next == NULL){ + return zxerr_unknown; + } + MEMCPY(out, next->rcmvalue, RCM_V_SIZE); + MEMCPY(out + RCM_V_SIZE, next->rseed, RSEED_SIZE); + + if(next->ovk[0] == 0x00){ + MEMCPY(out + RCM_V_SIZE + RSEED_SIZE, next->ovk + 1, OVK_SIZE); + *replyLen = RCM_V_SIZE + RSEED_SIZE + OVK_SIZE; + }else{ + *replyLen = RCM_V_SIZE + RSEED_SIZE; + } + + if(!outputlist_more_to_extract()){ + set_state(STATE_PROCESSED_ALL_EXTRACTIONS); + } return zxerr_ok; } \ No newline at end of file diff --git a/app/src/crypto.h b/app/src/crypto.h index b36ae3e7..f3bc8628 100644 --- a/app/src/crypto.h +++ b/app/src/crypto.h @@ -51,7 +51,7 @@ zxerr_t crypto_fvk_sapling(uint8_t *buffer, uint16_t bufferLen, uint32_t p, uint zxerr_t crypto_extracttx_sapling(uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, const uint16_t txdatalen); zxerr_t crypto_hash_messagebuffer(uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, uint16_t txdataLen); zxerr_t crypto_extract_spend_proof_key_and_rnd(uint8_t *buffer, uint16_t bufferLen); - +zxerr_t crypto_extract_output_rnd(uint8_t *buffer, uint16_t bufferLen, uint16_t *replyLen); #ifdef __cplusplus } #endif diff --git a/app/src/nvdata.c b/app/src/nvdata.c index 355d2bb5..aa2a2521 100644 --- a/app/src/nvdata.c +++ b/app/src/nvdata.c @@ -216,8 +216,6 @@ output_item_t *outputlist_retrieve_item(uint8_t i) { } } - - output_item_t *outputlist_extract_next() { if (transaction_header.outputlist_len <= transaction_header.outputdata_extract_index) { return NULL; @@ -228,7 +226,7 @@ output_item_t *outputlist_extract_next() { } } -int outputlist_more_extract() { +int outputlist_more_to_extract() { return transaction_header.outputlist_len > transaction_header.outputdata_extract_index; } diff --git a/app/src/nvdata.h b/app/src/nvdata.h index 7e7ff9e4..5aabe06d 100644 --- a/app/src/nvdata.h +++ b/app/src/nvdata.h @@ -128,6 +128,8 @@ uint8_t spendlist_more_to_extract(); // shielded output nvdata functions zxerr_t outputlist_append_item(uint8_t *d, uint8_t *pkd, uint64_t v, uint8_t memotype, uint8_t *ovk, uint8_t *rcmv, uint8_t *rseed); +output_item_t *outputlist_extract_next(); +int outputlist_more_to_extract(); uint8_t outputlist_len(); // signatures