From 29d4480a35c4accae8668ad7c224fb665b076206 Mon Sep 17 00:00:00 2001 From: Christopher Tarry Date: Mon, 13 Nov 2023 14:39:37 -0500 Subject: [PATCH 01/16] store transaction elements data in fixed size array --- src/calcTxnHash.c | 22 ++++++++--------- src/calcTxnHash_nbgl.c | 22 ++++++++--------- src/main.c | 32 ++++++++++++------------- src/txn.c | 54 +++++++++++++++++++++++++++++------------- src/txn.h | 20 ++++++++++++---- 5 files changed, 90 insertions(+), 60 deletions(-) diff --git a/src/calcTxnHash.c b/src/calcTxnHash.c index 7c36d89..e361249 100644 --- a/src/calcTxnHash.c +++ b/src/calcTxnHash.c @@ -160,33 +160,33 @@ static unsigned int ui_calcTxnHash_elem_button(void) { static void fmtTxnElem() { txn_state_t *txn = &ctx->txn; - switch (txn->elemType) { + switch (txn->elements[txn->elementIndex - 1].elemType) { case TXN_ELEM_SC_OUTPUT: memmove(ctx->labelStr, "SC Output #", 11); - bin2dec(ctx->labelStr + 11, txn->displayIndex); + bin2dec(ctx->labelStr + 11, txn->elements[txn->elementIndex - 1].displayIndex); // An element can have multiple screens. For each siacoin output, the // user needs to see both the destination address and the amount. // These are rendered in separate screens, and elemPart is used to // identify which screen is being viewed. if (ctx->elemPart == 0) { - memmove(ctx->fullStr, txn->outAddr, sizeof(txn->outAddr)); + memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outAddr, sizeof(txn->elements[txn->elementIndex - 1].outAddr)); ctx->elemPart++; } else { - memmove(ctx->fullStr, txn->outVal, sizeof(txn->outVal)); - formatSC(ctx->fullStr, txn->valLen); + memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outVal, sizeof(txn->elements[txn->elementIndex - 1].outVal)); + formatSC(ctx->fullStr, txn->elements[txn->elementIndex - 1].valLen); ctx->elemPart = 0; } break; case TXN_ELEM_SF_OUTPUT: memmove(ctx->labelStr, "SF Output #", 11); - bin2dec(ctx->labelStr + 11, txn->displayIndex); + bin2dec(ctx->labelStr + 11, txn->elements[txn->elementIndex - 1].displayIndex); if (ctx->elemPart == 0) { - memmove(ctx->fullStr, txn->outAddr, sizeof(txn->outAddr)); + memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outAddr, sizeof(txn->elements[txn->elementIndex - 1].outAddr)); ctx->elemPart++; } else { - memmove(ctx->fullStr, txn->outVal, sizeof(txn->outVal)); - memmove(ctx->fullStr + txn->valLen, " SF", 4); + memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outVal, sizeof(txn->elements[txn->elementIndex - 1].outVal)); + memmove(ctx->fullStr + txn->elements[txn->elementIndex - 1].valLen, " SF", 4); ctx->elemPart = 0; } break; @@ -195,8 +195,8 @@ static void fmtTxnElem() { // Miner fees only have one part. memmove(ctx->labelStr, "Miner Fee #", 11); bin2dec(ctx->labelStr + 11, txn->sliceIndex); - memmove(ctx->fullStr, txn->outVal, sizeof(txn->outVal)); - formatSC(ctx->fullStr, txn->valLen); + memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outVal, sizeof(txn->elements[txn->elementIndex - 1].outVal)); + formatSC(ctx->fullStr, txn->elements[txn->elementIndex - 1].valLen); ctx->elemPart = 0; break; diff --git a/src/calcTxnHash_nbgl.c b/src/calcTxnHash_nbgl.c index bad0fed..bd072b3 100644 --- a/src/calcTxnHash_nbgl.c +++ b/src/calcTxnHash_nbgl.c @@ -25,33 +25,33 @@ static void confirm_callback(bool confirm); static void fmtTxnElem(void) { txn_state_t *txn = &ctx->txn; - switch (txn->elemType) { + switch (txn->elements[txn->elementIndex - 1].elemType) { case TXN_ELEM_SC_OUTPUT: memmove(ctx->labelStr, "SC Output #", 11); - bin2dec(ctx->labelStr + 11, txn->displayIndex); + bin2dec(ctx->labelStr + 11, txn->elements[txn->elementIndex - 1].displayIndex); // An element can have multiple screens. For each siacoin output, the // user needs to see both the destination address and the amount. // These are rendered in separate screens, and elemPart is used to // identify which screen is being viewed. if (ctx->elemPart == 0) { - memmove(ctx->fullStr, txn->outAddr, sizeof(txn->outAddr)); + memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outAddr, sizeof(txn->elements[txn->elementIndex - 1].outAddr)); ctx->elemPart++; } else { - memmove(ctx->fullStr, txn->outVal, sizeof(txn->outVal)); - formatSC(ctx->fullStr, txn->valLen); + memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outVal, sizeof(txn->elements[txn->elementIndex - 1].outVal)); + formatSC(ctx->fullStr, txn->elements[txn->elementIndex - 1].valLen); ctx->elemPart = 0; } break; case TXN_ELEM_SF_OUTPUT: memmove(ctx->labelStr, "SF Output #", 11); - bin2dec(ctx->labelStr + 11, txn->displayIndex); + bin2dec(ctx->labelStr + 11, txn->elements[txn->elementIndex - 1].displayIndex); if (ctx->elemPart == 0) { - memmove(ctx->fullStr, txn->outAddr, sizeof(txn->outAddr)); + memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outAddr, sizeof(txn->elements[txn->elementIndex - 1].outAddr)); ctx->elemPart++; } else { - memmove(ctx->fullStr, txn->outVal, sizeof(txn->outVal)); - memmove(ctx->fullStr + txn->valLen, " SF", 4); + memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outVal, sizeof(txn->elements[txn->elementIndex - 1].outVal)); + memmove(ctx->fullStr + txn->elements[txn->elementIndex - 1].valLen, " SF", 4); ctx->elemPart = 0; } break; @@ -60,8 +60,8 @@ static void fmtTxnElem(void) { // Miner fees only have one part. memmove(ctx->labelStr, "Miner Fee #", 11); bin2dec(ctx->labelStr + 11, txn->sliceIndex); - memmove(ctx->fullStr, txn->outVal, sizeof(txn->outVal)); - formatSC(ctx->fullStr, txn->valLen); + memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outVal, sizeof(txn->elements[txn->elementIndex - 1].outVal)); + formatSC(ctx->fullStr, txn->elements[txn->elementIndex - 1].valLen); ctx->elemPart = 0; break; diff --git a/src/main.c b/src/main.c index fdb512c..f22f88c 100644 --- a/src/main.c +++ b/src/main.c @@ -1,20 +1,20 @@ /******************************************************************************* -* -* (c) 2016 Ledger -* (c) 2018 Nebulous -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -********************************************************************************/ + * + * (c) 2016 Ledger + * (c) 2018 Nebulous + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ // This code also serves as a walkthrough for writing your own Ledger Nano S // app. Begin by reading this file top-to-bottom, and proceed to the next file diff --git a/src/txn.c b/src/txn.c index 6b900e1..95f1668 100644 --- a/src/txn.c +++ b/src/txn.c @@ -114,7 +114,7 @@ static void seek(txn_state_t *txn, uint64_t n) { static void advance(txn_state_t *txn) { // if elem is covered, add it to the hash - if (txn->elemType != TXN_ELEM_TXN_SIG) { + if (txn->elements[txn->elementIndex].elemType != TXN_ELEM_TXN_SIG) { blake2b_update(&txn->blake, txn->buf, txn->pos); } else if (txn->sliceIndex == txn->sigIndex && txn->pos >= 48) { // add just the ParentID, Timelock, and PublicKeyIndex @@ -137,7 +137,7 @@ static void readCurrency(txn_state_t *txn, uint8_t *outVal) { uint64_t valLen = readInt(txn); need_at_least(txn, valLen); if (outVal) { - txn->valLen = cur2dec(outVal, txn->buf + txn->pos - 8); + txn->elements[txn->elementIndex].valLen = cur2dec(outVal, txn->buf + txn->pos - 8); } seek(txn, valLen); } @@ -193,55 +193,74 @@ static void addReplayProtection(cx_blake2b_t *S) { // throws txnDecoderState_e static void __txn_next_elem(txn_state_t *txn) { + if (txn->elementIndex == MAX_ELEMS - 1) { + THROW(TXN_STATE_ERR); + } // if we're on a slice boundary, read the next length prefix and bump the // element type while (txn->sliceIndex == txn->sliceLen) { - if (txn->elemType == TXN_ELEM_TXN_SIG) { + if (txn->elements[txn->elementIndex].elemType == TXN_ELEM_TXN_SIG) { // store final hash blake2b_final(&txn->blake, txn->sigHash, sizeof(txn->sigHash)); THROW(TXN_STATE_FINISHED); } + // too many elements txn->sliceLen = readInt(txn); txn->sliceIndex = 0; txn->displayIndex = 0; - txn->elemType++; + txn->elements[txn->elementIndex].elemType++; advance(txn); // if we've reached the TransactionSignatures, check that sigIndex is // a valid index - if ((txn->elemType == TXN_ELEM_TXN_SIG) && (txn->sigIndex >= txn->sliceLen)) { + if ((txn->elements[txn->elementIndex].elemType == TXN_ELEM_TXN_SIG) && (txn->sigIndex >= txn->sliceLen)) { THROW(TXN_STATE_ERR); } } - switch (txn->elemType) { + switch (txn->elements[txn->elementIndex].elemType) { // these elements should be displayed case TXN_ELEM_SC_OUTPUT: - readCurrency(txn, txn->outVal); // Value - readHash(txn, (char *)txn->outAddr); // UnlockHash + readCurrency(txn, txn->elements[txn->elementIndex].outVal); // Value + readHash(txn, (char *)txn->elements[txn->elementIndex].outAddr); // UnlockHash advance(txn); - txn->sliceIndex++; - if (!memcmp(txn->outAddr, txn->changeAddr, sizeof(txn->outAddr))) { + if (!memcmp(txn->elements[txn->elementIndex].outAddr, txn->changeAddr, sizeof(txn->elements[txn->elementIndex].outAddr))) { // do not display the change address or increment displayIndex return; } + + txn->sliceIndex++; txn->displayIndex++; + txn->elements[txn->elementIndex].displayIndex = txn->displayIndex; + txn->elements[txn->elementIndex + 1].elemType = txn->elements[txn->elementIndex].elemType; + txn->elementIndex++; + THROW(TXN_STATE_READY); case TXN_ELEM_SF_OUTPUT: - readCurrency(txn, txn->outVal); // Value - readHash(txn, (char *)txn->outAddr); // UnlockHash - readCurrency(txn, NULL); // ClaimStart + readCurrency(txn, txn->elements[txn->elementIndex].outVal); // Value + readHash(txn, (char *)txn->elements[txn->elementIndex].outAddr); // UnlockHash + readCurrency(txn, NULL); // ClaimStart advance(txn); + txn->sliceIndex++; txn->displayIndex++; + txn->elements[txn->elementIndex].displayIndex = txn->displayIndex; + txn->elements[txn->elementIndex + 1].elemType = txn->elements[txn->elementIndex].elemType; + txn->elementIndex++; + THROW(TXN_STATE_READY); case TXN_ELEM_MINER_FEE: - readCurrency(txn, txn->outVal); // Value - memmove(txn->outAddr, "[Miner Fee]", 12); + readCurrency(txn, txn->elements[txn->elementIndex].outVal); // Value + memmove(txn->elements[txn->elementIndex].outAddr, "[Miner Fee]", 12); advance(txn); + txn->sliceIndex++; + txn->elements[txn->elementIndex].displayIndex = txn->displayIndex; + txn->elements[txn->elementIndex + 1].elemType = txn->elements[txn->elementIndex].elemType; + txn->elementIndex++; + THROW(TXN_STATE_READY); // these elements should be decoded, but not displayed @@ -317,10 +336,11 @@ txnDecoderState_e txn_next_elem(txn_state_t *txn) { void txn_init(txn_state_t *txn, uint16_t sigIndex, uint32_t changeIndex) { memset(txn, 0, sizeof(txn_state_t)); - txn->buflen = txn->pos = txn->sliceIndex = txn->displayIndex = txn->sliceLen = txn->valLen = 0; - txn->elemType = -1; // first increment brings it to SC_INPUT txn->sigIndex = sigIndex; + txn->elementIndex = 0; + txn->elements[txn->elementIndex].elemType = -1; // first increment brings it to SC_INPUT + cx_ecfp_public_key_t publicKey = {0}; deriveSiaKeypair(changeIndex, NULL, &publicKey); pubkeyToSiaAddress((char *)&txn->changeAddr, &publicKey); diff --git a/src/txn.h b/src/txn.h index 01ab0a0..9755af9 100644 --- a/src/txn.h +++ b/src/txn.h @@ -5,6 +5,8 @@ #include "blake2b.h" +#define MAX_ELEMS 32 + // macros for converting raw bytes to uint64_t #define U8BE(buf, off) (((uint64_t)(U4BE(buf, off)) << 32) | ((uint64_t)(U4BE(buf, off + 4)) & 0xFFFFFFFF)) #define U8LE(buf, off) (((uint64_t)(U4LE(buf, off + 4)) << 32) | ((uint64_t)(U4LE(buf, off)) & 0xFFFFFFFF)) @@ -31,6 +33,15 @@ typedef enum { TXN_ELEM_TXN_SIG, } txnElemType_e; +typedef struct { + txnElemType_e elemType; // type of most-recently-seen element + + uint8_t outVal[128]; // most-recently-seen currency value, in decimal + uint8_t valLen; // length of outVal + uint8_t outAddr[77]; // most-recently-seen address + uint16_t displayIndex; // index of element being displayed +} txn_elem_t; + // txn_state_t is a helper object for computing the SigHash of a streamed // transaction. typedef struct { @@ -38,19 +49,18 @@ typedef struct { uint16_t buflen; // number of valid bytes in buf uint16_t pos; // mid-decode offset; reset to 0 after each elem - txnElemType_e elemType; // type of most-recently-seen element + uint16_t elementIndex; + txn_elem_t elements[MAX_ELEMS]; // only elements that will be displayed + uint64_t sliceLen; // most-recently-seen slice length prefix uint16_t sliceIndex; // offset within current element slice uint16_t displayIndex; // index of element being displayed uint16_t sigIndex; // index of TxnSig being computed + uint8_t changeAddr[77]; // change address cx_blake2b_t blake; // hash state uint8_t sigHash[32]; // buffer to hold final hash - uint8_t outVal[128]; // most-recently-seen currency value, in decimal - uint8_t valLen; // length of outVal - uint8_t outAddr[77]; // most-recently-seen address - uint8_t changeAddr[77]; // change address } txn_state_t; // txn_init initializes a transaction decoder, preparing it to calculate the From 2c188b2648a791a34752c0cbe6a3f344acdc87dc Mon Sep 17 00:00:00 2001 From: Christopher Tarry Date: Mon, 13 Nov 2023 18:48:45 -0500 Subject: [PATCH 02/16] remove displayIndex from struct to save memory, adjust MAX_ELEMS for nanos, redo test golden run (subtle differences in rendering) --- src/calcTxnHash.c | 21 +++++++++--------- src/calcTxnHash_nbgl.c | 6 ++--- src/txn.c | 21 ++++++++++++------ src/txn.h | 13 +++++++---- .../00002.png | Bin 365 -> 366 bytes .../00002.png | Bin 365 -> 366 bytes .../nanox/test_sign_hash_accept/00000.png | Bin 488 -> 488 bytes .../nanox/test_sign_hash_accept/00001.png | Bin 457 -> 456 bytes .../nanox/test_sign_hash_reject/00000.png | Bin 488 -> 488 bytes .../nanox/test_sign_hash_reject/00001.png | Bin 457 -> 456 bytes .../nanox/test_sign_hash_reject/00003.png | Bin 365 -> 366 bytes .../nanox/test_sign_tx_accept/00000.png | Bin 437 -> 431 bytes .../nanox/test_sign_tx_refused/00000.png | Bin 437 -> 431 bytes .../nanox/test_sign_tx_refused/00002.png | Bin 365 -> 366 bytes .../stax/test_app_mainmenu/00000.png | Bin 5049 -> 9534 bytes .../stax/test_app_mainmenu/00001.png | Bin 4356 -> 7669 bytes .../stax/test_app_mainmenu/00002.png | Bin 5049 -> 9534 bytes .../00000.png | Bin 4410 -> 8634 bytes .../00001.png | Bin 7638 -> 17008 bytes .../00002.png | Bin 2982 -> 4322 bytes .../00000.png | Bin 4410 -> 8634 bytes .../00001.png | Bin 4035 -> 6861 bytes .../00000.png | Bin 4134 -> 8178 bytes .../00001.png | Bin 6958 -> 14733 bytes .../00002.png | Bin 2902 -> 4331 bytes .../00000.png | Bin 4134 -> 8178 bytes .../00001.png | Bin 3970 -> 6867 bytes .../stax/test_sign_hash_accept/00000.png | Bin 4630 -> 8819 bytes .../stax/test_sign_hash_accept/00001.png | Bin 2835 -> 4175 bytes .../stax/test_sign_hash_reject/00000.png | Bin 4630 -> 8819 bytes .../stax/test_sign_hash_reject/00001.png | Bin 3509 -> 5293 bytes tests/test_sign_hash_cmd.py | 2 +- tests/test_sign_txn_cmd.py | 2 +- tests/utils.py | 19 ++++++++-------- 34 files changed, 48 insertions(+), 36 deletions(-) diff --git a/src/calcTxnHash.c b/src/calcTxnHash.c index e361249..1ba9163 100644 --- a/src/calcTxnHash.c +++ b/src/calcTxnHash.c @@ -161,9 +161,9 @@ static void fmtTxnElem() { txn_state_t *txn = &ctx->txn; switch (txn->elements[txn->elementIndex - 1].elemType) { - case TXN_ELEM_SC_OUTPUT: + case TXN_ELEM_SC_OUTPUT: { memmove(ctx->labelStr, "SC Output #", 11); - bin2dec(ctx->labelStr + 11, txn->elements[txn->elementIndex - 1].displayIndex); + bin2dec(ctx->labelStr + 11, display_index(txn)); // An element can have multiple screens. For each siacoin output, the // user needs to see both the destination address and the amount. // These are rendered in separate screens, and elemPart is used to @@ -177,10 +177,10 @@ static void fmtTxnElem() { ctx->elemPart = 0; } break; - - case TXN_ELEM_SF_OUTPUT: + } + case TXN_ELEM_SF_OUTPUT: { memmove(ctx->labelStr, "SF Output #", 11); - bin2dec(ctx->labelStr + 11, txn->elements[txn->elementIndex - 1].displayIndex); + bin2dec(ctx->labelStr + 11, display_index(txn)); if (ctx->elemPart == 0) { memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outAddr, sizeof(txn->elements[txn->elementIndex - 1].outAddr)); ctx->elemPart++; @@ -190,21 +190,22 @@ static void fmtTxnElem() { ctx->elemPart = 0; } break; - - case TXN_ELEM_MINER_FEE: + } + case TXN_ELEM_MINER_FEE: { // Miner fees only have one part. memmove(ctx->labelStr, "Miner Fee #", 11); - bin2dec(ctx->labelStr + 11, txn->sliceIndex); + bin2dec(ctx->labelStr + 11, display_index(txn)); memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outVal, sizeof(txn->elements[txn->elementIndex - 1].outVal)); formatSC(ctx->fullStr, txn->elements[txn->elementIndex - 1].valLen); ctx->elemPart = 0; break; - - default: + } + default: { // This should never happen. io_exchange_with_code(SW_DEVELOPER_ERR, 0); ui_idle(); break; + } } } diff --git a/src/calcTxnHash_nbgl.c b/src/calcTxnHash_nbgl.c index bd072b3..6901525 100644 --- a/src/calcTxnHash_nbgl.c +++ b/src/calcTxnHash_nbgl.c @@ -28,7 +28,7 @@ static void fmtTxnElem(void) { switch (txn->elements[txn->elementIndex - 1].elemType) { case TXN_ELEM_SC_OUTPUT: memmove(ctx->labelStr, "SC Output #", 11); - bin2dec(ctx->labelStr + 11, txn->elements[txn->elementIndex - 1].displayIndex); + bin2dec(ctx->labelStr + 11, display_index(txn)); // An element can have multiple screens. For each siacoin output, the // user needs to see both the destination address and the amount. // These are rendered in separate screens, and elemPart is used to @@ -45,7 +45,7 @@ static void fmtTxnElem(void) { case TXN_ELEM_SF_OUTPUT: memmove(ctx->labelStr, "SF Output #", 11); - bin2dec(ctx->labelStr + 11, txn->elements[txn->elementIndex - 1].displayIndex); + bin2dec(ctx->labelStr + 11, display_index(txn)); if (ctx->elemPart == 0) { memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outAddr, sizeof(txn->elements[txn->elementIndex - 1].outAddr)); ctx->elemPart++; @@ -59,7 +59,7 @@ static void fmtTxnElem(void) { case TXN_ELEM_MINER_FEE: // Miner fees only have one part. memmove(ctx->labelStr, "Miner Fee #", 11); - bin2dec(ctx->labelStr + 11, txn->sliceIndex); + bin2dec(ctx->labelStr + 11, display_index(txn)); memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outVal, sizeof(txn->elements[txn->elementIndex - 1].outVal)); formatSC(ctx->fullStr, txn->elements[txn->elementIndex - 1].valLen); ctx->elemPart = 0; diff --git a/src/txn.c b/src/txn.c index 95f1668..fa708f5 100644 --- a/src/txn.c +++ b/src/txn.c @@ -191,9 +191,22 @@ static void addReplayProtection(cx_blake2b_t *S) { blake2b_update(S, replayPrefix, 1); } +uint16_t display_index(txn_state_t *txn) { + uint16_t first_index_of_type = 0; + const txnElemType_e current_type = txn->elements[txn->elementIndex - 1].elemType; + for (uint16_t i = 0; i < txn->elementIndex; i++) { + if (current_type == txn->elements[i].elemType) { + first_index_of_type = i; + break; + } + } + return txn->elementIndex - first_index_of_type; +} + // throws txnDecoderState_e static void __txn_next_elem(txn_state_t *txn) { - if (txn->elementIndex == MAX_ELEMS - 1) { + // too many elements + if (txn->elementIndex == MAX_ELEMS) { THROW(TXN_STATE_ERR); } // if we're on a slice boundary, read the next length prefix and bump the @@ -207,7 +220,6 @@ static void __txn_next_elem(txn_state_t *txn) { // too many elements txn->sliceLen = readInt(txn); txn->sliceIndex = 0; - txn->displayIndex = 0; txn->elements[txn->elementIndex].elemType++; advance(txn); @@ -230,8 +242,6 @@ static void __txn_next_elem(txn_state_t *txn) { } txn->sliceIndex++; - txn->displayIndex++; - txn->elements[txn->elementIndex].displayIndex = txn->displayIndex; txn->elements[txn->elementIndex + 1].elemType = txn->elements[txn->elementIndex].elemType; txn->elementIndex++; @@ -244,8 +254,6 @@ static void __txn_next_elem(txn_state_t *txn) { advance(txn); txn->sliceIndex++; - txn->displayIndex++; - txn->elements[txn->elementIndex].displayIndex = txn->displayIndex; txn->elements[txn->elementIndex + 1].elemType = txn->elements[txn->elementIndex].elemType; txn->elementIndex++; @@ -257,7 +265,6 @@ static void __txn_next_elem(txn_state_t *txn) { advance(txn); txn->sliceIndex++; - txn->elements[txn->elementIndex].displayIndex = txn->displayIndex; txn->elements[txn->elementIndex + 1].elemType = txn->elements[txn->elementIndex].elemType; txn->elementIndex++; diff --git a/src/txn.h b/src/txn.h index 9755af9..e7ab909 100644 --- a/src/txn.h +++ b/src/txn.h @@ -5,7 +5,11 @@ #include "blake2b.h" -#define MAX_ELEMS 32 +#ifdef TARGET_NANOS +#define MAX_ELEMS 6 +#else +#define MAX_ELEMS 64 +#endif // macros for converting raw bytes to uint64_t #define U8BE(buf, off) (((uint64_t)(U4BE(buf, off)) << 32) | ((uint64_t)(U4BE(buf, off + 4)) & 0xFFFFFFFF)) @@ -39,7 +43,6 @@ typedef struct { uint8_t outVal[128]; // most-recently-seen currency value, in decimal uint8_t valLen; // length of outVal uint8_t outAddr[77]; // most-recently-seen address - uint16_t displayIndex; // index of element being displayed } txn_elem_t; // txn_state_t is a helper object for computing the SigHash of a streamed @@ -54,13 +57,11 @@ typedef struct { uint64_t sliceLen; // most-recently-seen slice length prefix uint16_t sliceIndex; // offset within current element slice - uint16_t displayIndex; // index of element being displayed uint16_t sigIndex; // index of TxnSig being computed uint8_t changeAddr[77]; // change address cx_blake2b_t blake; // hash state uint8_t sigHash[32]; // buffer to hold final hash - } txn_state_t; // txn_init initializes a transaction decoder, preparing it to calculate the @@ -77,4 +78,8 @@ void txn_update(txn_state_t *txn, uint8_t *in, uint8_t inlen); // decoded, it returns TXN_STATE_FINISHED. txnDecoderState_e txn_next_elem(txn_state_t *txn); +// display_index returns the current display index for UI purposes based +// on the current elementIndex. +uint16_t display_index(txn_state_t *txn); + #endif /* TXN_H */ \ No newline at end of file diff --git a/tests/snapshots/nanox/test_get_address_confirm_refused/00002.png b/tests/snapshots/nanox/test_get_address_confirm_refused/00002.png index c9222461cdd3ea49c300c4820e3704d33b9a3838..e90cd9db37ed7e4c669da0b1abe6e4a823770f3c 100644 GIT binary patch delta 339 zcmaFM^p0tQO1-J4i(^Q|oVPclR~<4CX?>`1PUW-wrFq@_jX}kk$&Q=C{_bC{yxi%I z_H^ILLJV*qDJUp-{om@BJF6JNOIGKE|2m}8FsJzEVy*Ar3abyaMl!6N-kAS2*sK34 z^NtmF3uIQ$mkDi&x~{%H3tZ zvTc^&QHE1ba^rn`=AOG#w&}HTh3wzZyU+KlI&I{gYm>a+wq>>Q5mm+5Cfld1Y|$6? jX68ChzTpPV-0__5jB!4tXL_t(|obB3M4uUWggyExcC+vSoXD>c9AxK+NNJwY!|DH5f zQqS}jFaiJo000000001hjLgi;YoBU*&+fn#%_`fKzAy`5S(fr*SMK%g+Q5Zb0MW|8 zxB3zBn%#km>IKKK`r$YOie0%)s~^4rJcerky-nDTWdPe|_^ zZ|I#keKYt8ATuqF6U|Oq^!$k3*m)GHKOY&)M+Wne0sf27-O%mi8#z;!_V%Yw9qR+d z`<^TcKC}GH?!b`dv zk6Zv{vkh9gndMc6<}wUO9Xc(j|DNyg+>kf~aQ< ke*gdg00000007+Y3sw)mR9g3FCIA2c07*qoM6N<$f+Jg>jsO4v diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_refused/00002.png b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00002.png index c9222461cdd3ea49c300c4820e3704d33b9a3838..e90cd9db37ed7e4c669da0b1abe6e4a823770f3c 100644 GIT binary patch delta 339 zcmaFM^p0tQO1-J4i(^Q|oVPclR~<4CX?>`1PUW-wrFq@_jX}kk$&Q=C{_bC{yxi%I z_H^ILLJV*qDJUp-{om@BJF6JNOIGKE|2m}8FsJzEVy*Ar3abyaMl!6N-kAS2*sK34 z^NtmF3uIQ$mkDi&x~{%H3tZ zvTc^&QHE1ba^rn`=AOG#w&}HTh3wzZyU+KlI&I{gYm>a+wq>>Q5mm+5Cfld1Y|$6? jX68ChzTpPV-0__5jB!4tXL_t(|obB3M4uUWggyExcC+vSoXD>c9AxK+NNJwY!|DH5f zQqS}jFaiJo000000001hjLgi;YoBU*&+fn#%_`fKzAy`5S(fr*SMK%g+Q5Zb0MW|8 zxB3zBn%#km>IKKK`r$YOie0%)s~^4rJcerky-nDTWdPe|_^ zZ|I#keKYt8ATuqF6U|Oq^!$k3*m)GHKOY&)M+Wne0sf27-O%mi8#z;!_V%Yw9qR+d z`<^TcKC}GH?!b`dv zk6Zv{vkh9gndMc6<}wUO9Xc(j|DNyg+>kf~aQ< ke*gdg00000007+Y3sw)mR9g3FCIA2c07*qoM6N<$f+Jg>jsO4v diff --git a/tests/snapshots/nanox/test_sign_hash_accept/00000.png b/tests/snapshots/nanox/test_sign_hash_accept/00000.png index eb5c3f3f9a3566794a05a93de7336b6d552477a0..aa1c990db293e4a2665623eedce965fb51dae1de 100644 GIT binary patch delta 453 zcmV;$0XqKZ1Ly;gEq`5d#2^TO(@t-)_dk+%=|g51R)hvkqnmu+lgp|gia%uA00000 z050b%_^*^A<=5-=|HdTPZM)2>Qi|4PwQGs^O)6B)HQ#~Cy^Ec}0jx|ZMK85xh2W>4 zy zndlJQ{1sFg5bF&pc!6HcN8f%B3?UH#wtcX*1)b=1XQ^zB{hrl(q-Mv6Y^&o(RC)^< z#|xt-pLqPF7ENLcvcBjJ#((?WrMGFV{VSfnC(JHZH-7^H_08~#uxUXh)QROS z6P<#azk(_QV!c5JFVU-b9NQ0qDI_w$J|Apt!616wSt?s&zi0LK^gJ*l`&9oCmEMBJ z@zSWtCmuhkMU&WqtS=5H<5}HK*SmF`$(@6DYIFl2D^wd~5Bg5*G4n+9a@&P;85 zY)_o2&23p4_J4%W+J6Eg?ps9f_)x(JxwoKaa>~k0U&KH&7=urIl>h($xI6CmfacW+ z$)My2!DSE0VTs@t<5siy9+CvMAWUPtVc{k`ndp1KYWaHuNy&f0f|Hq28-_QC!F-6p zOz{3p@cvBjKEOLvL#c*7QX)_dr5gIAhJ|YAWT=K-Ej|GN0001h$3r!gYUm>+0@ct} v>kx~S4{z46Pz{|7)zGUY000000Q30;%($SL{oIcV00000NkvXXu0mjfbw1fm diff --git a/tests/snapshots/nanox/test_sign_hash_accept/00001.png b/tests/snapshots/nanox/test_sign_hash_accept/00001.png index 768f1689624002a6817ba4e1cc7afad0077af7ca..276e1910596949c9e7e8b8d8a40fe7120b86a46e 100644 GIT binary patch delta 355 zcmV-p0i6EH1IPoABms|+B_#u414NNcEr0k0R+e*?OU>+{j#ZWm*u=e9JO;Z>vDSl$|uTQK>{M-3p3 z8+7nC`lwnLe2dl{P@f#swcsLh-PP1U--{TeQIDYj0AMBV{{b_ZZ)($8@F#e& zoY3-!*+0gaUYPf_m_N2mJ9rjv!cY&>CFsQ8EJM7c3LT_(kzM(}xk)Db(-^5H`;##T zPofGv=^)9>!L3Ly0000000000000000001Rn_u5-pqQrAhY|n)002ovPDHLkV1mF& Bsnh@f delta 356 zcmV-q0h|8F1IYuBBmt0-B_#vF0CAB`Eq{0eE6X{{rDk?e$12N(Y_I!xQGR-dD}$xa z+?J@SgNj-=de`x~nM3M|YmT=5$c*K+U#S-M4hX`Sb6XnC@TyU6EN_j-Etve}qXrPi z4LW!meN?Rr?xJ-E)F%gZEx3qWcQrN8IPbl2TY9#1Q?p`DQv1yHm7we5GO8^2_N#7!Ihg>SSNXNIJcN(>9`(DH#jrtl20036v{vR-t`KC6l1%HAU z%Ly%ynEhj%>4kY;i}_>Aw1a2yCQQi|4PwQGs^O)6B)HQ#~Cy^Ec}0jx|ZMK85xh2W>4 zy zndlJQ{1sFg5bF&pc!6HcN8f%B3?UH#wtcX*1)b=1XQ^zB{hrl(q-Mv6Y^&o(RC)^< z#|xt-pLqPF7ENLcvcBjJ#((?WrMGFV{VSfnC(JHZH-7^H_08~#uxUXh)QROS z6P<#azk(_QV!c5JFVU-b9NQ0qDI_w$J|Apt!616wSt?s&zi0LK^gJ*l`&9oCmEMBJ z@zSWtCmuhkMU&WqtS=5H<5}HK*SmF`$(@6DYIFl2D^wd~5Bg5*G4n+9a@&P;85 zY)_o2&23p4_J4%W+J6Eg?ps9f_)x(JxwoKaa>~k0U&KH&7=urIl>h($xI6CmfacW+ z$)My2!DSE0VTs@t<5siy9+CvMAWUPtVc{k`ndp1KYWaHuNy&f0f|Hq28-_QC!F-6p zOz{3p@cvBjKEOLvL#c*7QX)_dr5gIAhJ|YAWT=K-Ej|GN0001h$3r!gYUm>+0@ct} v>kx~S4{z46Pz{|7)zGUY000000Q30;%($SL{oIcV00000NkvXXu0mjfbw1fm diff --git a/tests/snapshots/nanox/test_sign_hash_reject/00001.png b/tests/snapshots/nanox/test_sign_hash_reject/00001.png index 768f1689624002a6817ba4e1cc7afad0077af7ca..276e1910596949c9e7e8b8d8a40fe7120b86a46e 100644 GIT binary patch delta 355 zcmV-p0i6EH1IPoABms|+B_#u414NNcEr0k0R+e*?OU>+{j#ZWm*u=e9JO;Z>vDSl$|uTQK>{M-3p3 z8+7nC`lwnLe2dl{P@f#swcsLh-PP1U--{TeQIDYj0AMBV{{b_ZZ)($8@F#e& zoY3-!*+0gaUYPf_m_N2mJ9rjv!cY&>CFsQ8EJM7c3LT_(kzM(}xk)Db(-^5H`;##T zPofGv=^)9>!L3Ly0000000000000000001Rn_u5-pqQrAhY|n)002ovPDHLkV1mF& Bsnh@f delta 356 zcmV-q0h|8F1IYuBBmt0-B_#vF0CAB`Eq{0eE6X{{rDk?e$12N(Y_I!xQGR-dD}$xa z+?J@SgNj-=de`x~nM3M|YmT=5$c*K+U#S-M4hX`Sb6XnC@TyU6EN_j-Etve}qXrPi z4LW!meN?Rr?xJ-E)F%gZEx3qWcQrN8IPbl2TY9#1Q?p`DQv1yHm7we5GO8^2_N#7!Ihg>SSNXNIJcN(>9`(DH#jrtl20036v{vR-t`KC6l1%HAU z%Ly%ynEhj%>4kY;i}_>Aw1a2yCQ`1PUW-wrFq@_jX}kk$&Q=C{_bC{yxi%I z_H^ILLJV*qDJUp-{om@BJF6JNOIGKE|2m}8FsJzEVy*Ar3abyaMl!6N-kAS2*sK34 z^NtmF3uIQ$mkDi&x~{%H3tZ zvTc^&QHE1ba^rn`=AOG#w&}HTh3wzZyU+KlI&I{gYm>a+wq>>Q5mm+5Cfld1Y|$6? jX68ChzTpPV-0__5jB!4tXL_t(|obB3M4uUWggyExcC+vSoXD>c9AxK+NNJwY!|DH5f zQqS}jFaiJo000000001hjLgi;YoBU*&+fn#%_`fKzAy`5S(fr*SMK%g+Q5Zb0MW|8 zxB3zBn%#km>IKKK`r$YOie0%)s~^4rJcerky-nDTWdPe|_^ zZ|I#keKYt8ATuqF6U|Oq^!$k3*m)GHKOY&)M+Wne0sf27-O%mi8#z;!_V%Yw9qR+d z`<^TcKC}GH?!b`dv zk6Zv{vkh9gndMc6<}wUO9Xc(j|DNyg+>kf~aQ< ke*gdg00000007+Y3sw)mR9g3FCIA2c07*qoM6N<$f+Jg>jsO4v diff --git a/tests/snapshots/nanox/test_sign_tx_accept/00000.png b/tests/snapshots/nanox/test_sign_tx_accept/00000.png index 4b927aafc92a2765e00aac931064ae8ba389cf8d..a54c460412b17544072f3e89583b1d7291886f8d 100644 GIT binary patch delta 405 zcmV;G0c!rW1Fr*+B!6~EL_t(|obB0L4#FT1K+$U43Hx7C_u_|x7M!eahef~rH}A(D1RgET%O%3A9+F?MiV>x z)2*c1kNk{}?o|*%5YyC}JVtTXd@t^x{gSF zdPGh6Y}Ies0O@}zF~yQm^z@CMhU|Z&DDP`oYV(Y~#j;F64i*{#mk%k^(-nJmF@W;Y zHyR%!++};iX()Qz>j@SB0000000000Slb)+ZICWXqYedp00000NkvXXu0mjf)Iz{$ delta 411 zcmV;M0c8HK1GNK?B!7HKL_t(|obB0dZo?o9fZ=S~O}PJ&a+m#xhLDMkm4PAUeSS$xb%5r|)VSbAA6y+jx1S=Gpxf_5=T+_g=FLXfiObH2 zx&EB?&HUNK$DF?e?MAG45zhgJ&)j!AthE;HW|PHsQDlFn<+A_aM04EHUj25te2wEj zg!z9`oF`Gent!tm--g=9XX0;}h~@y)2CV&fA==tvjNj(EymYksNsFchvCl+35sd16 zMI1$RS8t+6WGZH>{>lz0e@n?Fo{D0mZ}c?e{~^VAtyR(18GDQ6S%LyAGy@(VQkJJH z{_0`^)va$dKSp@V_J-3?^tRU%EC2ui00000006MIUljjZlPvj5jh+Ai002ovPDHLk FV1lD%%kuyL diff --git a/tests/snapshots/nanox/test_sign_tx_refused/00000.png b/tests/snapshots/nanox/test_sign_tx_refused/00000.png index 4b927aafc92a2765e00aac931064ae8ba389cf8d..a54c460412b17544072f3e89583b1d7291886f8d 100644 GIT binary patch delta 405 zcmV;G0c!rW1Fr*+B!6~EL_t(|obB0L4#FT1K+$U43Hx7C_u_|x7M!eahef~rH}A(D1RgET%O%3A9+F?MiV>x z)2*c1kNk{}?o|*%5YyC}JVtTXd@t^x{gSF zdPGh6Y}Ies0O@}zF~yQm^z@CMhU|Z&DDP`oYV(Y~#j;F64i*{#mk%k^(-nJmF@W;Y zHyR%!++};iX()Qz>j@SB0000000000Slb)+ZICWXqYedp00000NkvXXu0mjf)Iz{$ delta 411 zcmV;M0c8HK1GNK?B!7HKL_t(|obB0dZo?o9fZ=S~O}PJ&a+m#xhLDMkm4PAUeSS$xb%5r|)VSbAA6y+jx1S=Gpxf_5=T+_g=FLXfiObH2 zx&EB?&HUNK$DF?e?MAG45zhgJ&)j!AthE;HW|PHsQDlFn<+A_aM04EHUj25te2wEj zg!z9`oF`Gent!tm--g=9XX0;}h~@y)2CV&fA==tvjNj(EymYksNsFchvCl+35sd16 zMI1$RS8t+6WGZH>{>lz0e@n?Fo{D0mZ}c?e{~^VAtyR(18GDQ6S%LyAGy@(VQkJJH z{_0`^)va$dKSp@V_J-3?^tRU%EC2ui00000006MIUljjZlPvj5jh+Ai002ovPDHLk FV1lD%%kuyL diff --git a/tests/snapshots/nanox/test_sign_tx_refused/00002.png b/tests/snapshots/nanox/test_sign_tx_refused/00002.png index c9222461cdd3ea49c300c4820e3704d33b9a3838..e90cd9db37ed7e4c669da0b1abe6e4a823770f3c 100644 GIT binary patch delta 339 zcmaFM^p0tQO1-J4i(^Q|oVPclR~<4CX?>`1PUW-wrFq@_jX}kk$&Q=C{_bC{yxi%I z_H^ILLJV*qDJUp-{om@BJF6JNOIGKE|2m}8FsJzEVy*Ar3abyaMl!6N-kAS2*sK34 z^NtmF3uIQ$mkDi&x~{%H3tZ zvTc^&QHE1ba^rn`=AOG#w&}HTh3wzZyU+KlI&I{gYm>a+wq>>Q5mm+5Cfld1Y|$6? jX68ChzTpPV-0__5jB!4tXL_t(|obB3M4uUWggyExcC+vSoXD>c9AxK+NNJwY!|DH5f zQqS}jFaiJo000000001hjLgi;YoBU*&+fn#%_`fKzAy`5S(fr*SMK%g+Q5Zb0MW|8 zxB3zBn%#km>IKKK`r$YOie0%)s~^4rJcerky-nDTWdPe|_^ zZ|I#keKYt8ATuqF6U|Oq^!$k3*m)GHKOY&)M+Wne0sf27-O%mi8#z;!_V%Yw9qR+d z`<^TcKC}GH?!b`dv zk6Zv{vkh9gndMc6<}wUO9Xc(j|DNyg+>kf~aQ< ke*gdg00000007+Y3sw)mR9g3FCIA2c07*qoM6N<$f+Jg>jsO4v diff --git a/tests/snapshots/stax/test_app_mainmenu/00000.png b/tests/snapshots/stax/test_app_mainmenu/00000.png index 9d200b0d921e7f9dc37e7ae8d9353805cee16e36..61fe7fa59938ff5e808b075a62d410801a9f4093 100644 GIT binary patch literal 9534 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 PTooq=mt*Be{BHgSP;t2^ literal 4356 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 Id>EYdclg>a!vFvP diff --git a/tests/snapshots/stax/test_app_mainmenu/00002.png b/tests/snapshots/stax/test_app_mainmenu/00002.png index 9d200b0d921e7f9dc37e7ae8d9353805cee16e36..61fe7fa59938ff5e808b075a62d410801a9f4093 100644 GIT binary patch literal 9534 zcmeHtXF!wPmM$VqDIy{upr8~HLXjpVfT#$eiuB$~q#1fIBB&^!ARPiyrH3vpASh9a z0Rlv7#E1bxks3%S_to#rnYlmi+?jLE{G0sRd9(M*-m5&%+H1Yf?&)hXpXNSIMMcF7 z(YkY=it5BmDk|y%25R7ml0io$6_pSzAZr4BXTg zsUJsQc4y#v6wiNIi-C>$@i$ejb`R`#gL^mWR7vkUT&JVsdZtY@)DM;O(dw)UREXeX z0*00<8p!~ndcbNa_3}k&z}O>!`Mw~KX}p#Bce<0 zVYwQIFj9huXpMV$rjGG|;6M7yZ+Wzwmf4m9oanbIRXyd##jZnz0Fl478a~=zVdmJT z4IJpVg7-2_Olv>fNdx`6uD{8c&Rk+QYCL@ku#40X=dbfehZMJ?<6y9=c}mc|-oG1X zFM6Ex?)eC1cBz*d`DiXuj7JVw0ZcIcf>agRo@fS?@o&bgn!#@jPt#TXKWzN#gc15> z2Wt^d8uA|a=sXW&|#N`R~rLmwCSB^wm&zmA@UO*u=EHH0RvY zza8{zzo^)(*KN`0flVc)4nNCwPn)7O8$+=l70>A5uN_+fl^aX5Jr|T*%)vR0Yy5=u{ zh+dF}A>Iy3$7LO}odD!bjY<<^p$k$TEQs*5=J~RC)o}R=8adES`t}MrKd*sE6gr8$ zD4zDMgPl@tS+mPkJR4mTn|ZYK)`yAFLTy&S2Y0^u_GzVSJNYRZ3Ne6g*7fg=a(*wZ zR`!Jc`QF+5=8WX_kfcl*6R^Q#?V0UURdH91X=7-s(rcuaV`2XzarMtf=Ko6gdl>x} zG42Qe%V^W%qr=o=@TFvQIt?ziyT@L*B06hCkOqkCxcBZSzZ)@tnC_;s=HKGupd;2e z1bnz)BGd7Vo1^c}0%PhGgj9AJR3mp@kA|afMCQdOPzNA_f$rmQSJd%S@s4=?Al;At zb>|GY80A16CDm=tcC4Nq3R(&Cv@{%Zqg;1)I4=xG8?u^nSy;)xvIypjiEHVYsTb(_ zMNQ4rTSQqrp|!R0TY zZ?t27#qhsj%fEmq{^jnNdB-B%#Uiqe-8|2}QzgrMV zC=`)CUzvbeYMk`E8?Ic%6cb0c8<08c?G^;>#QU~p>Ot%x4cU`X_`vpkq-3p|#oc7C zDOPj$ZDos3MEV_Z%R}%A``}jT*s}GRs+TIOo5U24WsIYCq`8A)Qm$c zPj06O?uum$2qhHe|M@h}ug`k7SQ)Ytw)R6iC!##){9xy<{FZ(`e*Q4BrPA^WdJDht zZqideXK46z2C>bcmJVt3theo~`QrDGx%r2|;7eGdToRuAYXp!O6uQs=(!p%|D`^-S zcMZ_Lwddssodj&Ny8BS!wM$5=brPzmoPIU1U0q-nBim^$v5V)6hQD=i;KBx!l)IB2 z?yLw)4)``qesV!+TZX{hB-p9F7(g8&Ot)poZwNPOD3fPKzk>78fXI#DnRQbC#j%?g z^==tY#%i?R{&2~T?BB2}a|t+UrzBr+Lia5bi*!Tw&&SH%bpBPj%faNg4%ljLOu`6L zaDwpViWQ__s&&Bb%WcE9{621j2&TFw!bKWh2kSRwohDXz@@{8rG)2kDaQn8m$ zw%baIA?eWmnvxdjS(U*xMC9avZF-64aKLO*<;$D25$207GY*SC*llm8vi=tl^dC+m z|5J46I}UH7>a~{0s0ZasaL~jM+mi6P`d3k~9;p>u)q#2(&JG1zBT=|M-f4i_p%@v_ zp3NuY1saxt0NMWP-EtVDjdVh9!M){^oGdm1+x5E6;Rd$AC|E*aaGUe-`kH{Nvb}<| z*z0jbj}+6R?t@I1$tC|O@0Q)?N%-wSIe{d6J;(;T6A_jB$Z`B{b7@V5G9@wwM40KZ z0jYu^mCk#@4Hu<&v(EQZ6ZJyi%1Hvusi&8?Q{lB_%T2Qy*hg;{i=QELbv2%owqIen z&1z+_9Fd{}(kK`h?J?s)IeBg1e&os#4Sdbh>4dFVRM3245VCzOK$#_zY~~aN+Zk_H zn@e<(}i;c|ojrQM(zUQEQ>;;*ga7>+Ce@ zC6v2!X8m^Mf~MLE{_`wA%$VZ5TS%17BU|J;r-tGFBDY$Msxk#ZMx+SVseNrWC_PHt zzSa>;Xb)@iw%S-Dg$YHW2@U&FVwI%*V4{!gcIA?Vpg8gh;zywaS3Hb2XHA?U=mS0~ z?!pAj?irvQ3?1|KR=a(QK4tXN7<6%yrh%N-saqn znMeFdPJT0HNm+1Z${r&Kir+&@(n>K-XN~VAZi5c+o$EE|w#1L^v)=W^lXCkXfVi`= zS2+w;rmjSrVY;*|tJDz7jG6i|{V6-WJpncpP)aQ>V0P_(7OB&=c9-Z|HI_{2>yRSs zdN8)Uk^wXIlIic`4$0TW-Fyybhz$+NUELL35^{0;45B&Jf;|O2U0bs%HZ66*^#f_& zA+n7T?kZ|?SY)=k#^`r3>dHCimolghTQyJ()&rl;W5pMsVK`QMd!XEfPo?znPSvZ_ z;tj3UhKB+cRU7yekklK@#>i*l?*5FQ8($P(`$gS&+4oAwS4VMCgmz-9_w)%2*NGJF z#F(9J{3=6L8IeUag@eeqH1`!MYM1FhBcEb2Dq9W0G^{t{mHhGDSh9&ej--Mf*s>;T z+u42%Y_-mvN;ADI*-xD|G=ZzE=e!-%3>$vN&aa0dF&=*jB5k%AJU7E`;Uhw3ITISg ziCx-zQzfkEEr9g0OLK-?+h@s0KAQK#M2pG%1B2->IV5t{+n~%SyEO0?v*kP6ODLE` zhK@>kiRWwxwwmxoNgUX#f!6VFJ#}_?qt2t>6j7t~TVbNj_@baJun{PK`XgQWH5`EZ^ z_=gJY8n7;0s^BX%Z4@5XG96HxRtja;2!TIw2=25kF_@3+$|36IrwKwvZjou|Lmb?c zMePjGHGoc6+rvU^%0J1jS?0Ifl_7vlC3lDFOBCAGVkw7fZQh-+MYrg1S0PuPP%x?Y z=tL&$GN$g7?5euYpT;OXoDSe@@?Hc^*i>8=t7Rv4FucCD5THjeo30u1iO~qjb1)@F&?tqW%C!u04dCa570xYi#nQ%0MNakU}|f$g)5Svx&nvXyTp;&8ZnP%Qu3aKvubMAxtN z@F2-rF##DDJKc&>XxsFvY5;DN`nl|*@#NkIym^9AHABc764&&YWWKk;o`x3{ia0}X zq}6~0T;KewL(Mjl^}8a^U3*wq*Ye2^O7Xuk)o&gK?Ot~-ZnrS6!7z&+;1kzt2yI?Z zOjQ`daka@$mX9|AU-(D0trc8>s@pe7Sg>o9#El+DHcqda?tA14KI0Yg!ncOa>3sE@ zXW5zF0N}2pwVq%x@;e?bYzKqkb2{deD+N7jbCfl5)iliArq-bfUG(F1XVV*=@UjCH z95F8<++kK$kBDV1J|-H?-UV!=yy#EgS2yVy*lx3+WltPg9sDs-@?bZ^|?Ec=%KMdp2tZMhyj`B_Bvi;g;L%#&KnI`5( zhX_I=<}mAHd)ETM#0Q1avZ@?~n5>0qK;`)t3=59Gb+tE{NHeV(K8dT|t6 z(z$D~cm;LVPc%QkzWn$78hsL_6%ln>sK{YGzY zz+r|89a9SeCt{&ZU5vL`vHTX5uEemWow*?Nfe3`WFJ^ZR@I-88(&L=&% zwC8mxUK|a5g|n?SYY0sdOq+X5Zs;4jn^5=`yimCDY97WreMZtJtUfrug=2@5MnAiI zOtai6v*QKig4%YU?t-%wTVI?CJ!$g+%ad=NK6kbwfe#-~U`RCK4D zda|IH;5w1ouX_%;KEMg;q!UK0EV(($bIYjfEQmV`jHa>DsPm#qt=?=pXls^Vd$x3= zI@eGIN8acvODykb%0)-0#*nRfTyxSw99L$u98o-ahVTS<{(V-O8lq__q1@Tj^#9Smki?)bdTD+(}pODQ5E!@X{D$PERrt?{!zwAg2rkSuiVQEVrHN7j&w3 z&L5MSW_nbh{B5cfy%h4Js_zD!sg+S>|G+Vd49@e@$X8r;@XSrMHH6aaM zp3>PpRh8t`pJfLXNo>al7`-l|bSfpKlG96$Hn;sE4`?lfw7IiD@}C1#^NDdjl^02h zz7x)Id26#^bOXioMG|A*4qP8oQ`O-v31TdUK0uGI$PRrR-KusGjp;-6!qJ50dGM@K z^R=PG{sUV4+8%fzL=V4W`?GG*Ku1i{RC`)$Ii*x=*|+uJ=;(-qi%Od;n?5~xTwp^V zFLxjbuoHS9CxuX31{IBs_+c4<;?FMg5wCqg0TYw5m=_L0=Ff4p;f*o~a*0vnqJpge zYYAoNb@}c}R&Pgrp7^ljuZ?L$zuP@~W@i)@&{j9m7LBEmh{;Q?F2F%#m&Fd zR=5JMZ7}f~%bk7Y8B-E~TDrnY?hPtI;mw=6%XtFD`Zcs^F4ypgLXl;zNV$*d?GNp+ zf}XGcBTvz**9djCF7(ddWB+&{%Sd4S1EvG2;J-822b7!ewWTroRq38olSSfr zx(WRH%e3dnS$s#FqJKE9Mbivx09PkG8yg)mU+xPu*e`zCtPAWI zVqbvDY%7%0o4ORY+f1nnyjjt&;b(9r2V=OZ&QLY#$o&=_Kxb;m{`1{+oHfZWX&IlH zBKWGyOp-p`hG`^N#|GUZKfUrU<5!b`{cvZPz*=z5$N*;JZfsI&sJ%+|n$YXFtE~+{ z-aPkZ2VA=;kyyg*|D&q6zpMhi6@KqVHIvhY!}8ld9m6#p;*m}M6U~XSO*f{G&%N|j zopp_h2n_$S>E8iVa`%1Ks+J=7+PcnNY#eCZ?50KtTMPZJF8%ka@o)W=@=TB1^<*z2 zhBbtf$^O?WoRzW;BafFJ*?ZG)SpK0s^5EjB!M|$#O>8a}Q!*RdxhKqBnY?p8mwGYo zhV6uRR#Sz*gV+n|owG|l@?tJVRBvXj;rhVeI*w$w`>vK_`ECQr;OdhC;LbpP;|MpB zP|H5$`8ccK-KMSdGyR1Ngjo2Lx9}U-(a$%~u$8u~IESw&dX>zINE3iB(_N&u5(X`~ zHC_?h0+lkM!!DM7gxbx`tu27L2JcA2c-<`0OUsFEDc(O{&8xElS3Ft0)uH~5m?Zpf z{J43!c6#5P^JX)@4^X+_=KIr$6FGcj=NUg2QaLT00x;P%%wvV_DmGld@H zZSBtFdod2Y2o7X|l$64gQ(^-jf0pODI#MBfX-MB>3Z86f|H>2>t54eb715>o-q__) z@CDDwuN}*o!JW5UUyBZm4(bYF>Ic9Dfmhoa=~p=%HBS^znqTY2DAu~4iabw7AfMkE zT=2ba;q*!FJ-qi$uhfgeMc-B}ez^YCtYn||*{NBpO^HDJ&$~Qs!>NrIW%cC}u6))W zUDjbW$7$(r25HfK4s@1{6*Ok0VRHr;+ea+zT6uVrp4@T>JS%A%dSMfML*7!QgZkXxC9A7287tl$Biiol(D*X=WSFeyJ)4+QEWf zZ!>dfwJ^L&xe!Vp9 zD=QBb8q;Xn4m>)-80~sqTn?TZ7jHSzGmb7Rx{Vw0dr4z#&pTnp;}2PDpbfqNZTg3z z_kXGz_n($g{<{$KznlE0I-~!*E&lXY<6EsI@+GJdqUx;SZ44(tDhMqR`}=7|p7Z-n z!`%-C%HyK4qm|P9h7R5h`gy@(O2pPrtcsRpDxO$S(@{Rb$!;EKEWYYQjeM-Q^CR5a z(o_5j;;E=T^oK4mj!^hL{+!NXl@Ekt(E2OWZpTTtMK{TrsM7eRUt(vemUX>|u_o1L z#t>R!H*3+RO+Q&cqo;@0VzcBt?6a~3p|o#ZzkJV<@j!N4_6X5Y31q7^xSj^4n3n(# zle(`|N1xA;X%IdGy3|4y{_KMOZdUeV<67Y1DowsT!kvlQ&Ji9z|2Rg&@`RmB{NVSj zHL9^pQN&x@6L#*)+CYDo>VYnsIk2Ku4(PCQ1HJ0LGoT8y?u?w86b)veeJw!GF)l{+ z#W@Z1;BTF{>#p`Am#jPMK@A{^|Fwc%_UaxD-Qon83qUqdIKjoDt%gX63A&h-!1j-@6$+9N0#vktoZUz|J!N6_Dc?(P(JM~sld?1YXFOLuZp`~wn3Ri6Ska~2wNdldJb<3MFu%TJ8gL~ zu1D!S;+K-l=5MfLca8O8Y}t8wUSq^?Ob`MjRT-p+uKTVH3sOwa3lSL^3XvfWgFZ9P z1(0`iKP5Ab%egbIuf98@&&Z}>$gYtVbJijqD5ztW#@_XNw=`q`DNn=Xi+U;9D~O5i z+!8OS$$pybB^*0V%&fYwnr$t%*&`09Dz9jz6pJKK4!s@yyKq=D#XNnBbVyXLjokCX zw{zcl8l_(US^v`ad~M?Xsz}U2+gf0|-1O^y8%;;0q;sgcAC_G4HN;SOhTt*<%k z){E67n0kpj59Vs>=49O+-0#>s2qV||Se|U{&s=;UkKS4lOQ|7d^AVTi-5o?ec8~aM zzds9iv9OikY)!}@gao}dZX;Z*bg;664fotj=(aqGBbA7C;s<4KkLJ0Fqn3cH2g~v% zAA8k{hGRO}Q`l}}i4_HfJbl30t}E>kLK^~vKz5D$bkHgx$Q37+WjO(-dv1y$@Z>8oL-q*%Tn!{ze5^F%8hVQj9b~rT z(gre^Q+`pnC4cEjf7N^;Zuy+V3-ms?Q|^y$!`JL>lMCIq+2n2eS0ZhJtM@J~vK};) zyu-x(M|q}KfS!fmgD%|h!2z)G2|vO^g|BK;oGZ?0Kw0Sch*BFR*#yZ4x+_4*iHRCoYy_fxH**nS}&-bhYY_FUm4>P$`7t)FJ| zYWXRPd8jl^L;G{aVm#PyvRy~pBh7$Y9u9VdxpTT?i36x-0#x5dWb9K znG2W|gpkc3*4WNj@4)+wJ5eTcpJ2Q=QvR;nWbD$AsMklp{KkdxO{OG@4O~h=M}#G z4Lqf%L82DjoY|pt!M~vJjyict_RuQD*kUzxXwx f|BEaS?3V79bq18KECBCCQ9(5H@6_C~fAoIqjt!=tm2;vv1)4(+IHj107Ha0FiN~olhw4_A zpkkz`C?1@LFtxxm6w$Pkq@rd*B3$frzQ4Zpt#$9Y_pZCvy??&LZ~yjsp7-5*KW~PU zgRSg#)$I}z60&xGvv!e?*pee5vGsxURVZif8J-F(iG|x*u{w7U4nco#q&mta_w+$X>*$H>%I+lM@dM z;it%+IJd>FKpADjkmD;MmCzPM%~6x{ga>D}n?a=KNyKe{Vnt`1?~FL(CFmKnrI@Aw z3GQieKcR6E@ljG7G;E%8dyk-EpdF<&8g-fnR$n@ z{=~b1IvvEkUh$fIza3MaV-{f)m@3(EtPPW{)@t>xUn6`k;s;aQNS~3JvY#CO30cU< zRq$bxsV|p`cK?G~_T6$e*nHX#bqLbXJ^gXKhIc6KPlBo8`x2q?L%=GP&2(z%z7su7 z3kEm87epj6UG{~}M$g&rb-`TJOTpu;hCIJ-*FOHY{hT>AT@0_r5UtV)cNcytWvbXM zJY5o?8oeq#l1{m8tgzu|M5VI5-3{4qT{aU&F z_`aCDTk3{%JR)eW_3VC+!IzBUSpOB-)Qxeejwig=ud`?E$x;TgvYXj2+-=BY63HFc=i$;ISWk2E&;HR3OoCn6eqLD_Q--J_RE=0R3;JW}u2RyhQFukK}(|-W>mwMu#kn`7??Emh9 zB4*1^j}uy18!A2{<7BX4Cv__HOyvXpid1o1PK6F^Y0QK#8C9e*JJpphc>xhsA6^Y+ zrDPF~=TTMeDnJ~FFs&2Q`>9jvX?nwuY z%#)>JBX(BqF_TtKPs|z;*r*srZl_LNJ|8arP!Y0o6dhP`>GOUMb(e`!yRlb@+7x({ zK4{7m)5$kxnWUn(WuE^+Q@tDNqPO8ErIH9=hj1s{KJTEOkf zV=IaO5j2J__$gl=GGMYdeD#teQm@TVDsQ1A?8s085iWJ;e^nt08?Q_CaFbfWq^mxp zMsA-zAq8HGD63qW&$YI9kbw~|;+7>Rt!+FYs@=hsxvIjojU-3m2q80b52AM7|3;UI zYLIg}dB0;Sk;aSMchoSe`VG0mSPE)mRPoe{wQ~*mP z!t;-%ch;}1qmfRtlIloj9jJJ@;60aD88y*In3FQ(PB}#g<4Z;nHbJl~OOl7wSC!P1 z8o4f9$Wg#_sub!dkL&5xIEgv?{PJpj1M&*LH*s&`VGs3XI$bXBaFJ-r3v(9K&APme zIz{A6NL|#5i(wy8V^kD+vrgJ$I)gyT7PB2!q74@EBhU3bS~5d%PVqzHjmpd1wYJMB zhn}l8K7x0i2v%vi4O-{YiOw&m{H8QOja4dkVEoQEjIBpr1SMA{t+)9M+pwd%6AFc} zYBl88(?ZBRqSsFf6^OR#7om6`XOZ3;2b0#D=NmYObUP^N$={GnP;BaIQtL;nJg|vQ z5x#-K=mrL8q1-9{>-$c#g(c+o)8(Wzt1BkubgbChzPX3HR7o!vScb9WAtHivOgvf5DU?WUtRlPouNCG zq1*9mx+rTg{p|@nx~W>t@$L>2Wc6{ra8Laiw3YDSLK5#a*Nd8<t-hv3)QghcV zy0ep%-Bz*oUUnaBa`&CjUB4t9@c<7Hk-}qEsNQkTzQ#=Bx~~Tp$Tj0?<~%NtyTLsZ zglA)ry`t_j4zhB2NYi{V724iZwoW zJQ7?3L0;1$Z6V!l6(BFe#J<}&vF#`GzaD#FTtR?a*o5FFQxr9F?kD(M=!i= z$8Hwizi5+&;g+)H)`CO^TK4P4(g{s-f082pJd;=2vJCs_l&vRor)xUgqHma`yTL;^ zMW0lU@sPW^zr~YjJ4n zM#>WHT1y*PWCt7?v!pgr1#b$Can3;wL05!0L6Qk@OdA`T)OsJ~!`q@5;#LGN4GTCv zcwfC87<6|wo!Z@5m{@SHz|11PbtU%vzL8nQhIW!%m0)SWr2ok)1l^cFt0O2Wpvk?x zuUo(9uiuY~SZgxdHxe3GT+d&fwVt42UpeEvq@gj}u_RF5DeG&EP1WQt@631&g<;hc zJ{OhmQ?)Ra&%J3`#%rcnHGRD^Gf2_S`i zZBeB*bu8J9F0=aId)G#eV{KPI5&P4yoa*&)d*Ylt9+!XVz%_0zXIx8pflaZWCvQ}T zE9*G%1V=_l{2#_}x}1!fG)ooE%-^1+RVvjhcHj7#2F(v|@^1`cme3ir8iQdrJh9WzZHPD3yjI z_k@ohf7^seeFDwlOgx0n!=EcXCfCB;QjD?=)3-m8wT+qyqywOU2t5gKB@2I!>Y^3@ zxQ|x33sQ%X!j0nlQ)XUk|Au`QNpLp>88(Z3aW^ihLBJ{8Lvtm2eD{dc%3U79gip=n zrz_!meW`Ly2{{2`Y1weto-dWQIyvO*A7nRROY~ z*Xu3nbcve1Vn#Wfu`RQ5yRBQEn`ILEvfb&Ts~-bxPUb5@kjFCKa=(J`ig+p2OLc_h zLXnTR@@wQQq0Il&7*3eUfAF-+lJ-o=R+?deZjO(RiCo@H@xR_TAv!gI6XlB zcciIro-=!unB4~HtA^7upRrQm?8bNQitH6Li>2s6EI>EBHPKFCFT%o!UpG7L1{K2M zE66HZtxX|l{xV1=){{^z>~N>h(Ziw<7ouh+y16H2rcZpiY)6Hmi7Re>CX^S4l}dzK zT@EtInf~{J9b|6)7{_!KQS}!GGWx&+_O+x>f47>uA|_Eh!RhLyMnk2Wb=Gq>B|{gV zs^5bFqQ--QH)++8DLkbtz@N8z^j2C-qZ?tzi%BV;4H@nx%Yc-C97(Ggv5x1=?J5kU zVxKwT-0NIV)BY%;eRy0Z!0=HU)z?3DrbB)oexMg#GyKcLKGBq5-FtThFwAJsMNa4UA? zeS44W6%i5HXLbGBpCTeVo{5Nv7D zn~v!o`vQF3B@{*DA0GQ%;z;bHqsOjG9EcrB^Rups5ZT|4h-6OkD|VmJxPu3qzZVYi zP(C^0A`4@i6bA_`7U%83dFdU+xv}3dEGO5; zJda~4rciLtQ}H<@Of2T{>4vlMTf()g{vL=phauUC&BC%E`&uN@Mz)R9iV z>-eyx^{Pdicf+$i`@;5$O4_2dazAJqrUJVPE3+STG=F#J91{eW9fBu&cZGz z$~uNM=hFAZz$7%I_H=8SG)A1UKzr;sl{#vtVAN(ms9P6NoepU@q@^ixUP9BbYy3fD zMaMP4UP(X@+fk?d@Di}=R$ULntYm&^Z55Rwj(v1FVC|()Bl2&NUt<3=*H$EQS3$K; z4%UZ(ug7!-<*8dK##dL#Px$3@ZmM+g4}uiU`^h7ZEI*B|p-8N8=wGmK-q{TGkNmJG z&YYhQivJff0I3Or|_ec8Qn%x>nLizG?hQB`E1`G~T_JSr}hhkSy4wl~elS{-a#6X{h+!$`XXq~WQ{ktkp z)LYIR-&I~dL!2XOTT?lvkZ7SFwnT|=Yrz?$eJWl3u+bw@xzP)zPbLhKIh4ReLZNh2 z4RwZynop}QnWRs$Ygf>+Pe*W@==n}SeQL3WHMQ)}^JCE&Uu<7rI<$kea>6RTUmjQL zn1h`Zgf}!_c{+PwV9F{3JAExfVg8&ol{)=nB_ra>5mZXPX17o;^3X)Yr`o6{MzC_4 zB|&B5BCFq;l3B69or2;8W)!B z{$tcY6-^Mf!)56eMT#J)E@6zx`h4@!mLFCq>5~ud6rgbG^ zlT422N>z5iy#94FxoxO65vN<%Qc>=WI@GZ`q)_HcckLKI%(&3D>;+~*=3alaAMZ3n z8>b?j(8l?)QI)$Dq4ljqB~mfoC+C-`#yNpCNE9ibX(nf$(DvRYag0AT|8;w+>NA3F z|7p>t3^rJBZ`Ehr>N4ZY1@s1Bv^Gwlp(@MrJLU4P>zIrJjHGXQnJbfVjzUyppLf{TGU`Xyy=`AGB?@wO>dKCD_aszR z6NA0X0|L8(C<){j!`rk}wEQsr^&u}n!L>eal<_=@)GzOnEPZ?0(_IUhKzoSiBZ zlq8HXVD#lF5Hj+W;QG)dwf0d0mtoU89dZOc1f0G&5hL$9N#k#*(3``znuX)&tiX3g z8=V_x4Pj|db63!$>Xm^IccVXfxh`*9=g~xmDbSzs*4doPTOWnjhq{wxMxPV>Oi$0{ zuSXyJQKolOP)2bZbL$Sx+CGh^;&}_j1NGdXAmx=gy>Oc9e9rIg4pg|)#Hf$8?VDu{ z${%Qu)+$K<{yZn}{2%kn@%<@o&Rf@qT=!XKnfye-AowAF{}bCQnC&ces~jx#_Q8J} zWb32u>1-UIa#KxB4MbOC(V=|4QRF+Nove^oT}Gvh5*K&K?~8khGK^Dytre2g_8ttl zt{C6;$?#7+p>^t~B^zhh2OqFs2oTLON6DG%$M|JmlT6YWD43pWK1)YL&efmZ?Dl$U zbRc!4t_#OC20kVx73DLf8PU;&PNX-!Jubb`QMAibLBVlx+&XsI*ap`%x|q#G8mc}m zp5l?=%uO`KsS1#br(Bgx`mi72vCH%s_Dyu$%Eo4%a}Fypi0Ax`qy}!{(M7rvrD5MPGTV}O-6Q^-|-IJ zvq^d@Bo$dUsy54qbZ-XCtQba5-&mOYot1?It&XHUb>ZX zI`#!u9a;n2u6dM~RQ#bZ$AmA^V3{Pm&xny1i{Ty(fv&8rh4cLVb2^veT6GthcTp;z zw(wldtII+PkW>FUy*p}KHTo%NReo^!#a&{|EQ(hsL>+p&2?Y;Mm6@EIt#6oB24d3h zV02WJaC0N{-PalwV$qY|SmBPTBW!$E`fBhGo3h*0ug)3X#}IqluW>jPTl-)oNRs{y z0e5-I%~6pp%a(l1uApA1Q+ukXngEZGWNV>z1YZA9Q1yzSmP%qAOV)p=Gq2= zn*v8q4#aWYNXHMG_pe12Nc>8m;xyPaQ!hFNxfpZ~aL4e%7NU!G*I3YEqaV#SPtfzC zjibB%#tVWHOy4O{%9F0F{#FusHa@rh3In^7dp_(LZ7Mo&#Xj<{vwC&g2CU=Vf~J*z zQkk{&Zdz@vU?;bBk@q0wZsF$kQCrR8@je70GVM%_F=;QNuK18J^npFi!UHbpcDq++ zq{LdZ#?ply31eBG&wJgoLa_riZU?KUj_ums#Tl&)){GQ>Dp&+Xr2<2`b)h>vKBOl*tW0b#}DYtE}*zynOZXe!$tlm{D<*-mB; zBM7AL=EWL&V~-{kYj)RaMk0}jy1i;?U7Q<`%w49k@to<9^{phRc9vjGSyd9Sa!AgCk!G@Ka(`tEhFymr8VN^zd+Xo;UF^n4j4=$UQ(7;@Ez$pQXZsCItisC zp_4lNl=$Z(5#`(nvg>ZsTXK&(_-Kk-H9fZ%DAW%1$1#^gxgEHC8?*BA+JlhK4fh4l zYxgEonl`-}9&=hr4W1u3f!TPd16% za~ugEF!z~AfL8AswHu@YCH+dZbVA%&v~gi%$p@?S#mayx=K<+7#^Ogn8b=#OJV}U!r-Qo zgnRW+du5s88>^!FpAgokL&1LE4A+E0e00g*q_TFzxuGnMgr;x(@E3bcxEN3W-=lgANK=&*3^gT`-f zMvwf_sWS)*cX2Pg#0sVrzjVO5YNQqteMB3ULJq&R^btM z+J*TfAJ-;PlMz50GMfoBa2)e~cM2r4@Kfi55Ir~bXpggjSHUA*_x#J$&kq`0v~dui z3fsv6*=!-_x&_6H=b$u_Y`UWMTT(GctfSxOStm5Kko{y+@ZK-HV(^niJ`-Qx{Nr^Z zgJDL&VCDT zW1TgBxm?*3hnbv-%MyClezb-`&}cNn@!QlT|5x~t`2_mc$^tZ;dXeR?k9Kto>s7W_ zay_oBea=Hs+Rv}5s@JoQg-EDoXn4qqCA7u(%vGDapLr`Oq&q3w$<@P|NR~t49Xq+9 zH_mb$KtNR4mr{3RoBVtfR}gokImH<-~b>5;KSPU-L)^ewD&Vc=4M=F#el%mFFA!Rn+ONuh1D+6 zBpXwD-@u;NW7tM%MG)!|q2#04uX*)f1I=d#FZCYJ>JL)3R8{g;N*%%gMqPZ%#$rc) zzZ_>G7E{_j*9iX?e>hui{PLZdSl%(s%+55@QBCwhb=P0Reiy4-X-{0%|K?d`<8?#{A5vl?pc z9?=_+tr>eMn|5>-oc77t(-Te+%)A$Zp1oT?rWn#CQ_DiY*E8%D#+U#>Pg|JmQ(IY? zD!qKP=<(yi7S<2{gQh;NoFh(-VPuUY_IJ!^3#jPvuHVID{#pOn;D3h?bYiM;EzUsB zgVI?pTGmuuDatEj3Xl%L;9aJ-GRG^pv0le(3f}nS;Nbx{g%Wh0F}tTrqqi}o_IdSjY+!w2kAA3~HP>4&ZPo1&2nXw11p6IL%;-os(`J!Q z#09sx;vWQh2|R4v2JN{-?WAH@iNC@Z&{Ny_j)>spKk3NjzWz|p(IR2WFloqRXnNdp z;_cXeG1^lw7%0vrcht=73MRL*n&He|&wDC`Je1$*_{6bQ&)co*)`;5`gT9V6Tp|y} zE!?(~EA_d2;b1~Xn{H2Sr9;$b*ID;A-FIVu+vgk zF@e3GmOB~xxhZ=5;R-ktU=f>Wj6g#;YERIW(#jQ5SJ~umpAd1TvR{!rT2uHf`ptl4 zSJW;2g?Y8Vv|RAkH;W!Gorg1t`?WEOXtFCa4HfXC`^YYUXe>X;=fRoM4$F`iy(zXb z&i8?{>U}wpW{AEk}@> zlJ64?Gp=OTNiGj`AKfTZigcPy%&m_*(pkE+n}n<2u0Joo`=lk}B-b*z`C`PDRIVLv zTQB%#^aq>r{?C8uUB(g&?V2=_YBhPKkt^pTHs7aY*?#q61cR;w-NHX}FJg86f#Z>DuYc7vm*WLe++$fb#%+TANZFF^9E?isJAkD6`o$v2^NTG^BBphH#Igp_78CcY$}I{nh} zJ*9GOhAg~qmEQEjqGBYmCF1an3buOD9y;UbvLs~{rN;d3ec`==&Eylwq3OfUGIQez zQ|5IQb=Ss6cE-)==o|K(w(w1$J{~qFc2MQCrY%a^Q6Tbo;%IKKC)sr)oEWAv@-gMj z(x^|^$AHly7s25^b9ZvGU+$_Tmk4k>c7^`Vv)Q3(pX>Egdy((R8bku?u8t^11nR7) zemya8v8ueBOI(WJoib9l8X%dCO8c%J6E~IZ;@?p1=Ci#$$jL@_EuTTTLtpUlboGNH z4{|3Ew|{6=jT#heH)I!U3|oy8zWN)N)jxEx_BZ~KC%`xkN4(kkTiCVoVBXZIRa{|n z4MLAU!YdjzSeE&OrSlt}R4;fDm_aFH^$a|6oh}B3+R}V)b7wRP{M~b<`L0{M; zKA>*sKEytA{D$vR0})5(B4x#Vat=5Kq-k@iZ_$5IrUV~YdHK3fD4h6h2QUJe?_=0Q z>A$G2hn*bI$Bi;plTOg=_E(|X>_DF?$)f0=o>xRTkZ-K#f za&zD^?qwxGQnB~y3_wSr^v52+z+o}Rn%Xm52@m$%weT4jJM5YV8m6Sa^+1DU+*mw1 zsdynP3wF5c?KV7dtbwo}w3;!wHXZT@^{X2uByCdANN|!f2iPX$0>HdMH1JVtDrrRJ z^|2bZi=7a{@K%JJHI-aZz;t8T zvU+=pz?zi-?Q9FcG$!d;-`lyo3YVw^g$n*;J;HI9H=?N*QLh&G$$`_CZnm+Xy?lxv z^c{4jf=l2`%T(zk;IET5(~-GO09`2UtXn0B^=g{k*lR4x?QO*OpeYp8b}x!lukDzw zPJ=jC(=+Wo6tO->wgr4X|9b2-yZbK(@w^`GNuV*JzmhaDsB_Jo+^BBVsyj=>{mL#z zIS`;=d1ew{ouuP)vLDwxl&r-1M8tr>8Jix_SCwAZ9$!hta#Di)K5qn{y8|9Xk(S(m zNea*^?Trh)a2;;7K&i^caaCuF8X-kw-#g%X*J@~;_Cox-2tRSt1wQ|+QCR~6yiC+ z48n@&&pv$T*V_qg^J47W6pN0aC;?};zPH|Fzog{w#=Cf(a`8v9jw1K}Z(jS)01)$7Pn0)HOCxvbX+oTHeI(Yb4$S*(@c|TQ_2NIlkwt`8)8B_+F0g3HJOPp zlbK^KVCATQ5GHD);2?^O3YdmVsEpx;AYQun%l!xLJbjpt=REIop7Wmb`<>r=-u!QZ z{B-x2?$OZD(Dgs#b3sF6Td9V|_MZUT)gBKpwO&I*f1AJ0$xCS5!q`~yqPjlXN~$>LyLwy68l`&5rjyLcncgrym&hVpD_$~%Kpq`MN?Y^^MLDx4Fv}Hks-(v1@Airo9?K|hH9ekwo z6QSwHCZHd4=ThY&nOxaqA6X|FNT>%dlN+ys`&Sz( z);mdVg%3JpX++;^*f5vkeS6!Gx$Ln*j-f4bW((#Y=oKJ)cJulTDntaKSH?U0CXg}V zbNb%2vu%xXR}-y9D)7~`j*-h1!E9KymU893K}}nWQzk`^vRDOml@5a6-Y~SK8Kxt` zJh1GOIW4muOM+O7_BU;CAuGgnrdCggK@Vd2j2SeLFr!C|P}T{mHW^}Y7AobYC=hI! zRtk%s4OZNYAgJbvGgVucBRa_LqV;@*-Uzqf64J<@PFr-4@z|<_!F$u2k2oz_q9)0? zM|kAivVBi`UQ2#{R9Z}~X8Ecg-D|8VVX{`w0W&l;h8Y?B8hLb8wQ*}&CZk6!D z0ORGG0VJtou;+xV zaq~FQ#y-c5WKSA-WbCaA==ozr;=8HDkwN?Mfe^7j@Bl<-UXJuidjB%DTONRp79zd~ z^M^S9R(T9tez8;EQALH4$gGg12fI*2Ga{OziKtG|L>4?P*|-C zkwn)Gh^Xt_n;Nb$)`#?9RDNx!LK8Y3Ka%`#$HZ}q42mx?g_Y3|IlXMJrM~&>Rq1)Z zzH-fUNjj}o=69LksWQbBr#QsfKLRoUk_i<4*>^QrsYf5em=~u?1{ClB@XQ)!gWh@4 z7Xp2ubwv-j=C441u)#O8j%iU_gFD{*!Mpc4XtL_WGyu7Ls#@Abtfm=O@2IIb zq3ESnhTa&SG-ygzy0HNgA|J%bKSa1g{6%IL^!XutHfKAt=|^s+a3=f zz^*z=AIFETq0V72)i3O-fHT?F4RiNa-3LCy+ibm0la0j>Km_7S(()@x=5W;O_=r@u zbIJ<#vP!slwgI1BY^W}DiL|VQBF<)Pke9rFQ&xYQx_UYQ^3K1$(rs}1P%J!$XiPhu zGCn$e`f!+&)XY}c6#8QPks2T8dvtguJ$mbnPjMOjaV=!`i!^j)>($PFZJBNG%T%GE zLX~r+cEXT*%JpoKP-=dN4YI@?)1(T^ z2_ZqX+-<-*XKOo`-#zN9=91MXp|QS@#1!{EUnocEN~w>wL-~;#K1B|QBTIts`$c8> ze@GXZf&~I(x-ldeaS4y=10Y8dszz}^wUS)fV#e<)S(fw{DAzr?x|KpUB4FGAmZQ%b z3)_oHC~~yvHit&-sNr1EbW{boXYFq7uN#KtNLp|MGlaWE!Y7sdhm3BpGX2Kb(~)E^ zr^M)6El{o>XQK9)-hAH{8`}Ac{7_i6ajx(L`>OLx&v%C8uNZgRGjVjAohiIzgDkk!VL(8Zk`T+9~8;M71r@&9T6^xmD>uKNgTH6i?nTuWZIDru9N$lpNo+%?B<+2O736XWNY?)IoaBlGZ}l*isUX$27N5rLTUFwn!!2VIEvUKg)V6!;9I2o`n*c7WMu;lztU^oAukzn4F6zb zkf`|P$I^u&{f{V||6bd7TztQDErn2AQApzJzqWm961jBKgBj@iX+ZQ7W6a;_bgO5@ ztFleSS|U4IBoYk>e<=AN`!zE}?+rjQrBu6P{MV#s6rEIdgp zSTb*aaL8$~ZW08qXA7B!-$p1S%rZt8*CjvS<^9vmh2c>=4BjEA5-)a8Lk~Uz#WWON ziCJ_6AAnF$Ypdh9!y&{3&QSzgQOFYVB2n*3!(NY;_aTV2CEsx*OR}EBxo`Q>!C$rZ*hgx?pRdP{@*z|vur!9a#m3+doPu-dS*LtYJV6mHPqAaOUCtL9!Lya3j<+kgD zi>LmAg;Yh&+=0&J&N-vS>W$)BfWtiCCseF~BWnNvemgOzdjDLmjQPuFGZhVz<=9+ z!C>ksf@n(HDd7gh*zww03+5>j zkU4Qa_qz)1j3>tFgtRXLQ4*6&tc~cP-Jo89!Rv}F{}*pG!=P+BJ}z}Q$PiSa&qK7Q zy@Y~r84~bbLi4r}N8zKuMj%d~*He+z58795NF+WCqyzseAAijwW{JM=?BqAa=~s=^ Qe(AR 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 literal 7638 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 diff --git a/tests/snapshots/stax/test_get_address_confirm_accepted/00002.png b/tests/snapshots/stax/test_get_address_confirm_accepted/00002.png index 103b406ec46006ff8c81259a96c1ca59bf372939..50661614cf8c7d670db49c267ea1f2841a5d873b 100644 GIT binary patch delta 2302 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 literal 2982 zcmeAS@N?(olHy`uVBq!ia0y~yV4T3fz_fsa2`FOazh^ZA19z^ci(^Q|oVRzQ^B#FH zI9yCKi9VxNJ^75g$=Vf)#|m%m(3|sFGSEz-=Huj;y8r+Fe*E~6JE7|ToWCp#*MxKw zoHsP^9Aq+L;XWZS${7uV(R45r^FmMk`B@*I7Trv>y8gO!`pW~>E7q59gJ*1uw-VRF z``jV74C)8_%8WY~W_{@9z z+p(S=S^0fwk8Y<~8JRsf8h1`msQZO%Ij4J_cm0R*AN@Zh|F>U`sW@=r#v<`*OZOQy zf@k-&mX?2v)tlaapZRy5H-Fz>tD2uD|9|=Y_Vwnd8>~C5FHhW99=rbf`M}f8*WOs> z{hN1x!=L@PBY$5k{_#@SE_K;yW_ACo%g=~i`&uP?KjN=(EARWWCvLhmiuO<{vkX=F7A(|(YJS3^1gG`ZwcO3 z9n-h({gWwD`x2X2v(rys7s!wJ$v*$sHtuWY{kC^iPS0=l+2#G?tM|X6$L|iOl|Ax$ zWYib0|HWyBNyKr>*I)h%w%>c__J=e1`j6LN=hf}a_;TU-{4$ppn|K{Cpp?L;k=ZqeUUF#29lFNVZ18dPQzq6YrR)6Q)^*;ahPsekUDrPUc zcj(tk(f)YX{Lo5^*SA++dKb5L-?0-n7XK}=lrdbt|KGm%S$j_VnCmaSdGFoVv^$5a zZgtDo;`E7_0zLnDw#K}-w81VHnFB~ zh)qz8aA-?lltkyuDa-czRquIFdRF4xt*!V}Ld-ZO^8Z=(lm8cX@e5vi{qOv9f0QgY zE!qD=&DXEz#Bkb&+a;qighL-&4337|Xt-fyYbqv+|BT0S{PelH8jXPMZw60SKbLh* G2~7ZJ9V=1* diff --git a/tests/snapshots/stax/test_get_address_confirm_refused/00000.png b/tests/snapshots/stax/test_get_address_confirm_refused/00000.png index 850d9a69a338e95e5d13596965b3fe2a1e868fea..ee646ecf8bb37a8a999708fd569ca22cb3e118a5 100644 GIT binary patch literal 8634 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 DEo8s* literal 4035 zcmeH~SyU408ivV6O4C(o&TLQZI;}`0CrpLPhV3zPAImfqB{fOKDKo%{vXZ4VnC{XX z;Or(#B_MMIF(NY)r&35s5HsDPh)940!m-{_Yf%jq|J3`SA5tyon z79r^a$La?QV}KTh236TW^J&81yEEWqpaqeadx2Zp{pESfsmUngbrx9xJB}2545UF{ zax9;k6U@LjA-@!drEOsw?OjETscTE!;%)}sNE1^$Y0IGa`5thNdtS%=9$BDJfs?kr zxrCHQ5hC*S8QTciomXA1f7%3gFK@X!svb`Tv!jVsWXlKNfn2v;D1dmuiECKvEDSLM zZHWidt<&cB;r%r1m^eFuQ$cP!9&5uMXLLEyH1!{A{Q8k^OWJ|A|H+PKm;~H*P?>?} zunSGA$|E6uv}Rd+Ptfj3pv7)mA$aY`>BF?p7ZSw?e?-wD(}m@AybXd~bWem^lDuyHe#?a zm`e*q#nrgsy=a9k|yrhT=EGwxWtaBk?hel zvPHNrJ+v`(tF}qp2WO!gkDKzO7A+BuvKDjLdu8TQy&UDP)gChu8t#l~(X~EnK716c z7D^%IXXMtVWFTfMwrQ%*BZZY2^@h4age#UmtiPI~EW_Vws2HVAH?>4k;rMBcK^{

t^BLI=Bqp~9LLqg~FVgBRvKI&&n?<(m?yh`wNy@eTu5 z7FCOLDm&wo{ccY{DytV)<*K3lDt9c^gC}J@EqYZ*92I>r`K_-|AVvXfu9O2ik? z3SVe{BOx0@pZZ7}aEHIZiB#N_Ime3_pOmd65VmF~x-A^lL%XX#(i3I%;=-w{xZP-b z?Ffo5?#AB;8<|B#1%0iQdgg9%spnS@*N1?hsqGdyG@_97o=ZtD|38i2gPs5dP5Qm26KkMDRG*H8JeoPz29#sr^!dL zy;`r__vL3X*E+@Pyl$hr4#o-?Ma4PR-X&ug!x++wrR^XCAW+GrVCGIA)Ur!cs$c3Y zD-VS;ylspl@xvLQ%r0J*Xv0wvj}-Z-YLpwnb8gWsKI=rybjI+7qgrjF8*BkWnhFk= zEyjdKp5umQz_K_CD@#fr<}{M|R?O71r1+r~m%H&gomya%J<0P*%XdpZ@Bw+5P`axM zqUz!uC$*jQ{NzGL|L&9iUg3+MH%?rbpAVWe#WiFU--8GE<8KRJkCZfm=8Ht^8XpA^ zSXLQZm2*SrF3YgvQ5fOr3k7u4te6LTL@v5yI@7&q)qEz4)RZGk=+h;NTklmdL{Ckp zqkls6*(Dy+8{J%2L}c(|&JTFU==CE@_m)AXZ7HZ0zTr z^>Knn>XnV23zoc^QOtbqZNWA-ILNRF?IqD&l0&lMF9+AUHWRzPgtWBDHAE~QHZhge zJa9@HqflpzJt<}GLF-Oh>;7OOF3d{fLh-XW1Aka%7rt-LUMS+Z>Zl-D;=OD_1qIP1 z-@G8sp&;7i<;(<^1&H0sIiK6U!#mYV{<2?Fb z8%3Qe@A;J>F?U>41Vy>>u?zST`7dW!)WdfLbGfz(e;8120?#FxaQ_^JC?JPbrD@f6 z&`X+};S*C&TzVNv3}TWg!HoUQ>v95X} zxqvKeJ19BdqRTFJLcIH`Jgm|(Xd1^ixBlpgs_w_cg9b zDpo>lFQBgNJciE^nqB>g|QT^^mY_he`mk*zHnlyIQ_i#7-mSPfO&&?0fgoYstL8M`^5-1jclh|BX9tma{{=tVm6-ql diff --git a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00000.png b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00000.png index 31e63ae89e13ccbb9700ae4b1222cf07b55a6541..f1ce79fd812ab60f61587496549bca61f4707052 100644 GIT binary patch literal 8178 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 H3(xrv&}YOJ literal 4134 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 E4{A?{?EnA( literal 6958 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 diff --git a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00002.png b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00002.png index a76977d0732671c688573bb960cdde6cba96cfd1..64c696450d1d33e1a9bde95c51f5202c315028b4 100644 GIT binary patch delta 2302 zcmW-idsI^C8pgYwv8L1}OR^C?O=YK6Xqst+O4o53RL;~?-at()%M>*gR5p7ulPRq< z8?DedjboSbg2o^sDmA3mm~zqpi3AZ6O%V_kQ7*Ha{m0&Gy=#4If9rXF&+~|!CpMRC zIlcDTu_Fh6BvopLG$%Jj@qdalG_aQ*&);znGkoX3_q(?xt%}Sq{~z>eS^>>o8RA9v zIu#gmU%hy?CvolFrKxANk`h8iMFmrG(Q%kz1l<9~; zLFknTke@92s`Rom2zC-%c`ti=d-;6+d+>gUhn<~W+3N%i4<8-92JH%mr?gJ9DmWa@ zJ%PFwCbNmFiCG|M8y=3;BsMfObkWZ-B|1Jih{xebGFcd7-2N(0oG`)11>{@^qRVA6 z2Q>EaKqxoacdBeWvo$du=7ps77S;l?!by#02$abhhSYgc#8DkpDM}%xr8SZQ9UUD} zGGY7G;7{Aw^OIG~kE=Kz(;2O8ZRQhmV~2gJ!n9LUr)+6$&)81XZc$%HgTFx_3~XTNJXU&$i<*1m5cYO!aV zGEwBPN+1xNwyCUE3VFd3ZXj%0CzH!>`Da242AuqcgrR;z_s}#W_-0DX$##VPtDc%l zZ5!=W^fUbv$V&;EQg6XXnX%kCZyamiR&qZMm_r2RsV{L|WZD26iAs5QZymeuaJzKe=#sHz(#G1fUl3i z;p`u}c#P6>ukx3%6>4G4Vdbb7eiB|hZZ0Ugg~wWS2F!|y8xQ{CFA9H^N~I8IioI>X z6Ba2ltum2>!q`P92h)s44`Z5(eY)grYK3s*@|D;W{X3x_NE0yY;)+23FGUiGpg1T1F;4#3LCS z%K(-V(89n$Q2$ObXAl)lAinU5UeccJ5|jjMd{purRF zc8VJfWuW`D@Wp0iU84JSzmT&yJbsE)U6kxYzYsm&Vcb+?{TzR18~5#uHoMNwp~2UM zb@v5o$exfH3Et_=mZS+ptGN|*?rkmaOPS=HgGiUPj47E6JQoL%Ychc*p-`wxx6x=c z7CWd4$_p%&yyiqC$_?Hoa+><+#Z2cqV*@lnN^6@va{vCw{l`1n+u?oeKD9x3YqagU zF+hwYaqHe)nawFIsJ#>}7K_ztwR=Y2*xQ<4@@$p@gG3UM`hy&bz3}#j5lSCAJL><9 z?sBy7f_4!*0ww6^Z| zruE!93&5r3q~D&<=^9yUbJh%${2t7EsL;HNp%OkF4%#vMZAWTj`AvsY2uj@O2?n{F z^<7?G9@HmI5z-2?Ii;)q>y9o}Ji2txg`+ljF<%AV0;2Jq6_6~=K;pJd^IUe~2L%ylyFT6Ro$~}ur4tS@4 ztj42QHc>YeIbnkQYDZNc?NE%a8PkOG8+s1EA>C0 z&B`bH(NbbIv(C?WyZQ#6->HW1*Xhzo5_)B29fdVI7iIoWEit2;ttU!LLe+ug6x((8 zXL%+>5J7!$q4ok4p%W7m0`Fd97Pa7t0__!!=+S+}8xmidvMkaEpaRCl#Gtj@Gvyvk zYqMWHtEDB5Kp^+K_<_RMr7rpZN+1uqmUFg~z*%wC7N){3X8G-v7oDwk;~6D8etBvBZ3*-oI~sPR I;ZSV;-<8%9j{pDw delta 874 zcmV-w1C{*iA=Va_O-pPe{Erek%1zA#G zAVaW#48a021PjPG#ZM$Zu5&5;KT{xt2vyB%33%MbhY zO%6VC-MoxEac~|VeTDJg1>S2;w>)>tCYo@;5!UT?oATq+Tc-PrH~i?Kvxt@n@% zETRj42J6GD6|-@=PpZaG@2bA}es#S$+Fg1P^-c*t{d#V7yWO6&|1S^YAD!;_dDeT% zd-YS=1AH!`?yA3FutFZX;Jwbs%i7hc5Uf*wI3^kQeO!Hv{q-ol?%aoiMF&}eHO*l= z_VVk?%1f!QZo%5kLx-%nA7Vz2t`Po|aH5U3=dHeUwJ_aZhf&`?cir)J;j_XOcb4w; zuAV(&opMj+?n|leg29?Nd>Gk=4!F=h{sxLJe=|1=!ok||U5zLCcuVKpXTA=y&iOun zSG(Bk@U3vLmOXXzUA}j5`KHSIa6Ed8>3R0aZ_f%JIw{+IUY>oln6mKCv&K*2g29@& zjt6f9AHM;8U-#4P?g{&T&48A0u+rP*VA>co>lnbn+}1E(bWi)=nc(!X+XcRNa)A26 z5v*zMckKFRL{4;E|60KsIS3y)QiyJUG%(9+1?$;X43yF*GV4AcWR?r8rtn4gb?&cr zFF$PIuTQ!K?AHtMC%pA+wIkn6_f?k~9eFC&i*JSKOO z`cs!u+AE$C0#T8{9S%(UYR>fkb_G1-4EwARk&z=Mr}#HtTmE~f?;*mt`hV&*!U8e` z3&;>GAYKS& AAOHXW diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/00000.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/00000.png index 31e63ae89e13ccbb9700ae4b1222cf07b55a6541..f1ce79fd812ab60f61587496549bca61f4707052 100644 GIT binary patch literal 8178 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 H3(xrv&}YOJ literal 4134 zcmeH~`#%%D&SjT$M_0XT*Hyd0Q9 zlDh<UkOsudXSOeQL&+| zrh)H+x24C%$X#K;j^-LskoY$k4E$Be!?N>Fi5G`+{~RC{qpP8nj>%&DlXk{zi- z;g}moWPI*9wtcCOUQY2>^x|WTz}It3qY$l*u$1&6?jThoZ+ED5dcnN;T!WkNRT?Op z@xxagTW!>|`*xWB$Mqi!RQMa}-05TlWn%^FNVs}>H+=19AZn>YX}L7?08N;jYm$&d zl(Qdn7o`vBez|%vRcf;X?HmohYCG2fWpA8U6$GX<$U<_!+bAxxymp@emwSA@n0o4% z79#sBRhmwLDwj z;N19{31>|KHDj*F{>Gwr`JlU)vxgUuI4mr(AK$gQmzFuOb8v0m*pymLT^j2#ginu} zL7lIO9p|c(uH+*lA+|1R{Hh2EJW#ut(?(^n+PjPBrOBL+4|-0E-}S9zvadwy1((yL zW7+(Gm8s|BpES9tph>4hf^L*PWc@=oP{&7tR+d;Y8}lzw$?~&KiN#|JBC=cz!NbG zviyWL+}TMESE`ELd}0ADQ4hb7r*&dR-u%egMJ);xt14*=#gL!^C9d}3FA{y)Z25S6 zofjmt=26no%I7B;g-bI|Q|=_3_(CZ(=u-69eI*5(`u_Za;|4q}LdVB1HrZP|7RzXK zuk4*rS_A0MWqx^Rq8LX-J#`(+gk?^ZNT7D&l3{hl}UryND|S52BvkbbZkg&QJWum=7A5nw)kzHmd@yDF zE|c0hpm$h(79FsGt`wtltDvcub@ft)1RjYaVy`_9-Z64FX2fz>Q~guYHTI3SzwG*& zwjovMw!gV2Rr&r{Nsk5`;Gi{ z13+xmVbcWb|`(gl~q0Mxa`VE3|HW}EjUfn5=_?bscv20WM<&(?2Xo)+L+m$ z9Ns<@L9fGgHs0#v*iHzI(3Idh%;9M|7ynR2Dm;+Qcz#6?8&U33KiAEE>-SCgdgz~e zoQLVWt#{qC&#z{93F8rn=wH0!Yuy?4ZK*)`#pv%pPk?`K@D~neyHHU#E!Nj%3-?~M zwYQ^NO_?91&v60p7n)H?DwXoc)1PM>o116p#h9O17vQTdZ$zH#DQ(G5sQ$ zz0@i9l;8zS2uYe1t0OZmnQR$(TYBv!F!vgJy8JYr)ypr)m%S{Wk5-Fvuc741H_xh8 zhFU56?nw)smAexKQQ!;RwR;=ieFYW8->q)2C#I&R5(tDFu*6WoKuUs<^+JcZYN;P# z*0#E9uYIkBZKORW1BMw+Ru?h25sNwC(Jke^@;grki4qNX+$f0BuBbiVayz8DM<$c) zXa1f|n3?zXFx?G0Oo<(`B?aCO=0#mwF;1&T#kRe8?~e^4h49E&bP?M-CE+epcB0qsa8TUH!{G(wuAm|*j?R+ZtP%+;@{qu;r~IZ@#iH&J=V!Mu z-V>LJ2|7@|Xe3%QX*)OQ)Oc`B+tgxT&GjgXEs?zTK8kv-yL#I4NFAs@PO&C%4Ax?6AJUdvnDY}-(1Xbe%<$kpilT+E*NDrWYyKjz}@KJnt`s5$-z8J*qTS1%VsAr$(W+U(3@P@+q zI^}1!JbOfhjpQ~zgLwp=hnMN6*X6iHPthA7ECm2oPD<1Z!(!X?qo$?^Dc4sfAX?_DrYtj^G_@Rs%F4>rG6lTgwKCB(@d_x+*u^F+bxh4G zV~v{N-MpfbnfH<$BQyj=MHC`L0|W&Bud~)!>wGz1&RS=!^I`Tk-u>>q-`{0F&-457 z`(-z0tu6Xn)~#Eob>aLOk9F(TXRKSd;m^$*fG76u?WA?<^z$#AIpvvHC}c9?K21Km zcZHY6Tz4d6*KN%f4UY{LCKg>5>o5Mi|0M9!FXd1d?^HHN}F5@+IrX|iqLFQD?&6FO!?yEGL%7~*WfnpHv zFQUq!zK1+EH~fnq5n?R6yTUXNI@+I6AA7_?q8)w(&(Xj)OTG_1e{--e){&NO3_gap z^WHzB1^*qDoNSo+w78_wXz@VTGk5o@VU*9iV1uq_qXS84zP0*lhy1hJT~me@op}TC zhgoN9k5_g4wR9>v3|w{3ylu0NX_8M>Td`lm@e8$jQD-1e9>i?caowm}Lrm>BeA4j_ ztUq{j*OXS&m!Und9J@_*>x=C)b#Qtf1ZfD%0P$w;M&oYq+1j}nWCgFI&s{5^xIW`7 zxGOk~^R8an_l>5`KCQ4EpJ?xtp4Ik*f-ATN3y;GEbq6(diddNWr=I{r&d~=KbsaVE zFc144_rZ%wBGJT?Vru1C@`qPD~mhb-ord%;=qjQi3Fng{rf8)N*Iz0X8MeDSE zuvqgqy5dM7?1%6VYvP%ZuHjU`@R2hx!*bE2v4h2L9;qK#u3p{J^9BdBy6)-@n&2 zf%)D4Nvs(WyXpTCfKRWPx1xI7H%+6_u362a-j0r5mDG+$KtRa;TK1{I*fM2CpkaC+ zkH@RVm}U*c+N<7Y4&P`<&{D3f_)$2Z;7_38wKeJUvGxn2R>2uD6HKO~gM%L&u2QR% zYIUdTR|z^9gYjk6Gb4FR@{AzL?@#6<#)R?i?(Vem8}>zR<)iW>HM2muyu6GKBhmQp z#1^?j-JFF}`;tYq_?~C_x9ebjxBmd0QvDIyFrLwuYg{gjSB_-K78gC#BLV*Y`r0sy zT%oM@)jxZiGuiBfdto2~?)9FKmzIqCjs7(_^-8OM4F$15yn?J{s3knK) ztwb_0hf%9fcsMPF)%*ci?6t(5p_@CI=ME{XalleagzxZ*djSvNavHC_qxvO7$j2FP zPn8ZPQfmoe%?vMVlzmZg;U7^}MNw!hwzIR-;;K!N8|l$~;5=>u3*7-S0v4wS94lpl z(Af*`HpM#5PVEzBk}obR6h2Y4n3$^CmE%I0lA70UM8T~Z9p?s+iihW86|_-g&f?)9 z5TUtwpb|ntYKqlrwM$t;AH8xH;NE&m$TsQ~x^#ZN!Vi6mMBfB>79(@X_#%}yu?{!F z%$pduFq!eKeqUtDHg8(--6-zR_He+>+S=MQgNX=RiT=e#-V~pYuq`N>=wF=Oi0GS+ z?(nB;W0%A#>QxoSzUbp`Hyv&?jC*dSWer@jEjXfs&nmDUEa&GJ1HMMb&A*Fl<|4hL ze7$Sv@bG(F#pFQl0!tSe7uN{*DftpD9GD<8za%IhSIb! z%vjcU?ZAuWMD@w2FZ?438D9GwnP| zOu@|!d=vabj|`QF&f9q{6dQ?k_v%~L#NYK0#_|NJ3GlVW6%Bc zzG;ahj&3Hr(a_r38us~d1v`n`d=>MGZ|sOaU23xC-9Tmd?KfM)mL&o@`NrqG$9*AG z|5*eSijhKoQMTPsqC0@}Q$LtDPZ+i>TjEg(+~L$FAkVY3$0BTL$oD(AyXG<^X+j*0 zAwm$q+N%rqTwtcTTP^DEdL{2A?Utyp6lUa*yZV|{m_sPt?pkaAZRAL0(#b~k>f$2u zxWQnQTI%7>#AofX8Pc^{x!j1f`XtNQy4BR#{>!}&xJv$R*8^ES!F4`W5R#Y528(0? zxu?PgfKiPzzK3+V=p4U6cV-d@mz3mSu$>`nDxB=KT|_$Gv@eQmW+42Os?H=i*Yug< zeGX}Z#1!==782Fp&8cOJ_L$r>fA!JHDfuK&NtX zpXcx!yoP{J-7me^>N&CezBs8nTa=dNGQ!nkXdi?o>3=s$>6Ni0T^Hr2Zm}5@&~e4R zCxqVdhN&``Q7nZoVhGRU}|R{!`&wsP(9{Abiqhx$awo{hH13BB6Y zFvcL&M;Rlwc+TULCVAHmf-kf#ATtBws#x>}a$N=u+nwFW&p#_^h)WL7cG)w& zrFJtdGKjoTc&|$>8=uqlQ12u+;giqQDw=DbeD{%ME?HhqM0yCeyd)j7hef%C(seJK z2ywS?>X5%J1>khH0M!z`wBP|s+5>4UErSTP&FBnpur7w)G={!!`#9hhkQ>mB5sp|~ z7v3DG+6GVE`Z4NjZ_A){lfJJV|B+SJzzn=EJ|{}tn^T1BhG0CXD3iu4Mi1z`Nm{VG*5{f21qIYYubNVnXJHBWH?>dDew5t=Su>idwng~fw@xru% zcQ@dB7L{5jZ~{0e)~G3&%e_v#RjP}tkvRmR=mXlk8x4opn;h|2?xa&Z{ut{Zz&=|b zjT$~iBUe=+Zz`<0VfJKZ^@QR0QekLk#$f2Tq{7La(@bG}!MidLl0Utza2Oy@$Hkei ze%E?)Xyks9`Xy>i%IQMjW=UrU7hA~GV|kZ|=@S_>`M}-E&CSKPhv`2j4ReSd^#GWK zm{2rt{`(>2n61(w844Db({z!@dctMzQY1Te5hp z2vJqL9YVLCm0Qka*?bgil9E8 z%)*i%(rD1P-Az#me_>Rif-R#N*N2NY;srQ@pT`T!*K(yyq*$MjkRTM5A{TyR`v6(y z?m#MfkM7Pu?JbkAW&dm&A zbxloFR1{fS{9z|RRFaV4iN8Iy{XwDBx_!DR6GCO=sW|&+<$79=)D1ftD}Rs+apMha zdSbouqpu$3N#ECF)epTs0YvH`jlIT_%>5`O& z)1EaC?a83Sz<+*HjE=>Q>GAKRNYMP(+VH;0B8QRSuMX``M0%CooZHClZU?d!)5ePf zB?kESI0b7!=Dg}%6ctJNOv!f+>6^$aM;9dx|F+XWe7f^z0Q_!~H#jO!?#X?CNGEj+ z+*sybSJ=4`9GYjRQzZ72+Dur(p(1N-%PGdK?zXnJe7ACdJ;Yu=6R3Ma@5-KDIw0gS z5I-co3DV&j&(muH9(AmzWox>*jUii;P^fvf1X5hK#2Sr87dNbkUcK7^fB_ZidK*I| zy1OZ#(bTo_x{v{`J6oBhunIfDx$ly(xoH+uVRYi#L~i# z*w~`OGS?5fNCUgXI#CphP3ess6g^1U4Y%4D>&l<(W#l-%J_Sf(|!NBn{CAw*X#qzHuCTWrGMi0ilk|(iRWI%b< z*<3euRb3g2DSFY~oCF1=zCtRDXXp`E#E zV9~^kXVjapnM#3FYHbM=EWLc0mA+jL{~H28U@VXY?71^Eih!748C3*w>o4j>0ENoL zD?i-qkk@PA+Z7Zzqk*(W_m?fJ4AT41!b-pR!!+$`;}f5Nh+uYY+J4?5)kZ^Lza_}F zfCfGYKMZEUDdX08m-NZ2LnUsJZ#&!C%E2%lYT7UJC z;Vo16?Z)tlIR!pUY*rMgIy`s}&+*M4Oig}W9}y$>Z%J+qY!T+*#{7~&OVz5 zlwS7kb2EvU$5aH{1|2KmK>McalIw#|Zo9e+=8ekzFZ0_zoKlSd74jpperg&}wgE5= zluVHh2;*Ru5u$NTD%XcYtGd4oZ9HB+IuBeK`^h^4HmlnK*`BtXEkMTU1J zy369_stnrni7AX8}gW%4ovwE{(9G) literal 3970 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 G2~7ZMNxO6a diff --git a/tests/snapshots/stax/test_sign_hash_reject/00000.png b/tests/snapshots/stax/test_sign_hash_reject/00000.png index 0bcb5c34749d8bc5d932a6d444be58c63eb69c7f..0b41d3f3c2825230b578efc46cb3ecf559077aec 100644 GIT binary patch literal 8819 zcmeHN`8(9@zn3IMv`7?DQL?47ua8Ga6QahFJs~kfjBU(35}p*I5E`D8kzFP;7#TZ} zC1W4cU@%!`G`7KP=c9AZKX88do^ze+dtcZ6%jde+_j12qulM`&?3T5~p@Sz6^6~K< zvb=uHj*oB8OFlmSe}wpfFM2i&rF?v6^(?QM+=+NgBTa{u+$1J=u9lPdYz{0Ry?)?> zfXW__oWg?xj{KQ&3fB+VJ$e0drSr>XS>&DrXCGEXoW{SX1OL(RR!R`2+;hc>z{dw~ z;6-op^EKTOkl>U0cmKBx{=eG*BJT^|t&Po1AMM7*#yp&Sgp7bh#eBiR2=)4>eD@DK z)}D;{!$3GTzVy378(KXfzBCzIWj^x)B^7v0SQu2mh{v6+s(KSdNYZId7E)31x+j_D zRJ$)WexJ*6)1aWBHi>!90U72@!q~G5D)AB$fg#0pv$BV!4Ro$2c?$9iYfFi|=OS-D zXgUi_UbfQ$CdRHz)+55izAuRlt2><`lp4{}1h=CA&FYP;>q%9MJIL%A9BHRHF zYb0}|%xu%;ZN*(ncx?7$AlBsYY-Hnj!0FGgM@vh(1LZBN0~m%wVUXa%X5YIy5Sh+D z*4rJ*A`StQtmu9Rm>%+URYXjnF^I5!QCNMZLpz26&fS`y zkEC~}%R9{$p3qh}CU}AiGji`n6)2v@uv3?g!hr^ZZMmB?qWp}2W^Am_O!WNOh+-4B z+B?YWB_$(E8&O~AE2=i1iL^3HNj7UUhQ2BiqWWG+42D49hxD8)M`dMYwN*xspB_>O zRfWAm6&KcoiMb|0utdeAYLzuv=gdM{j&Ysw-`>d$3t%t}ijxy6P~16#yXHE&v@sC~ zT+85eKF%O(D^_zbV~M%n*vN<-_)m>OE^0gw3&nrAh_s=*8vFx_&_l8z-&X`=QY{dt zIAd_KQ2kReN|c+e_#p{{TF}_DA_}9n>-i5;r%Xz2;7dGiKJv$QC2Q7g<1N~-0Q7*I zIR8jzeN8{b3wtq6Zfu1q=BP9Ug%B(3m6=pVgtTl1LXCHQblsvZZ_4AME{B zmvpZFDfdVw$XO|cqG7e)qIU9(nSP$m)~}M1<*9g?sjlj8f<}`^lI1PghF>>KDLNSH z=jchKUyc!HEL$}lzcHx6fr#WkH35Z(s(0YF!%Q}ft%TvU9#>q)8 zYt|;>DD81U^%>jxmb}>Kl@qm0W;j#uxEX^+n6TB-PmxNP?uuTthup_vj~vGt7V2wV zs(OOpbT-$lt-#teUhfY*K-%x)_WrvetSX+oU=1DV;rOG+w^Bo*{~{UJnz{_XbHsog z#oG&Am3pc{HqjT~2;!!ZaKe;Vk?dkfzgBGocb>+4!|teY?&IeE&4aI^3v+ zuj58p>Doar-X7GTiN)2nr%<*Ak69N>xlHwSPD_ZLCP!S$8i?6sUwUdb6h;%bvt5j5rhbc1QF1NC9eQxqSt%ugc@8K$NK|! z`O^_nkY`v*RPU7R&FE`IvwKv_`aaIqpta2JI&uYXq<>K9p)ewJqyttMzI4}zp5s>? zsq9BO(xQod(Z&prSFuDUd9vy~Ws^jdl3r-==XU*>gQDy9REOq%TvM1N^Lsl@Nc^H6 zvzjzzQ8ydV$K@5 zA}@X5I+G*+!I8>cj%1Kv^tdZ8m4HoCbV-(Y1pD4ruJ zgpB-00J-0vZ5)DT`7UEaLz&D!n`>Sh^^!2>*8*lK2`>Bte zGUFcWyQD)mQ$eMEDhm4HaNIsNwEMN{6b9=1yiN#e^K&JH%S_^ZEadl31Fw-M`%W1a z;?&2UuGd+OKFecFzbnn0UP3rG(`CL^mmwPN{d#-M-FIp$jj$sd^{{UtbP++;3zin6 zyT!38cwa*Ojl+;% zHMN0bRBOfqN=ibG9hpQd)pJ?QmFY)sLiFZd>*8*Ux~ASlzcG|qCcf(|tuXaSY|2Fy zFYOF|gk*YaU23RU;&EA*EYmftE{L|NY2I4IySR>G7^JGtc!M~vU&pdGm6)gYrWAD1 zVgXy9y(Wz?U=5Dd;jfMjNi%)(sGEIsW;Cw{-tl$KQ!+)qGUo9ZjDzwsN0qNY^|5D< z8JB~i?hBW$z>Jt;)8UPO3*rMV)oAK9B1aziwXNGxm(sn9G{**3x2WZ7FPlR#x)yOk z46O6igwNl+w-txxpi$0N4jw_D$klIFQMp9ldh%FHQo&D{k&SdvBW8glb&8>#hA*wn z9L18br8lJx1m`j@UWhQ>j&k&r^l=)IO57BCZ5^4QuQEy)W2~g6it(bqU9;5~^f5S{ zn%j#)Yv!OneU;*}J6H?YcV&C#=9O#bu>1}Zou39+j+x$)3Aw!;F`-x@P4((t7!rl$ zp>Vxma7ISFXKldVPD5hXj~Q-QsyPD-@7~9*Rymd5Lzr$n*uk<7arkTP(gRP!2f3vH zk{H%K_#=y2C!<0R&_Zq#v^;5z&*`*g%t0%{*d{X<1Z_2n4z$V-v#pY1Z!5q-kea(O zIJC_9pNI=}$@78&lgVjErXx|I1->>}?ro&bDpbDVl#LH-(~o201qR1OH?W#M{wn$f z(aMd)y_X5AAzBg2?3GW*5@}F|>!dF=XRL?DjK(rZI4{+U`i6yyNjOmt(lc2_Ev4Cx z7{UE$Jqv*9bIP5j-iI}?p#8Fp5y{p(q71Ejq@h}KEXxSi$oA+D+U7PW0NJifl7 z@}%%9^@!I4jYKjTc!fFoTOTd7NF4YVAkG>RISWR_KYL3}xC;WD<}!5=(m}WS84oac zWn~3G0<(%$q%j(_Vt#@)pBjG%9=2^k>(n<@(~w;`;^hbzo8xf4;6Le6JFS*6TaNXFk@p&j4ZC%1~{(A7Jl^U2xhjD6~7Q-bk)RT*g z(P4sUJzf~=vFj*@H&FwH^mP{w2Q#J-mF}#-9jPH>!ie!>DEpu+0yzEF*47H1r`Em{ zW9W0&lnVNR>6!u??O6P6k@6_K55G{EGx=E%v5i(y?x|Mk>Gh#lKR*RKj$kHH#u64G zKS|_y2S}_G;p9zfPaQ(klxiglOHb4Oa@C8drl=7y^4$=nd9!!{ALyHV-^pIw%vPLW z<3hV*oquL|3Ffx^=S@yF{ag`pEBRR>GKCU-%LCa@y(sggd0T~&mBqOI)%SqH3CDA{ z57Xp-fGV#vMzS2<)VX_Xi%GvtG@R=^2|z6PDcJ1l6>Q~1n|3(+;Z?F*!QTu`x}X4m8x4KKInyS+VCdE)1YlKa%rO;ecjB~WoP)K zN{>1GRfoLg3{SmtxwMFwGK8qD!2oe<>)u$=x4?cQ8Ja|px04Zkh`G|-INL)h>=fiG)`rx$c% zH`D<-0;Pmko`)Oa4!$SBTclvd9X8nuMy3RfrHvgtkBifAZZW=((kJW}YPfjhd49_K zxdX;v{A&(8Xumz}vp(Y1dkC?=zyBHj79ZP@NYfHAMMzYPbal*p#yv&$d=kr>BxKVL zeFV%D`NLGY(|FV2uB>S-NKzmc5x+7;mb*u_bNX=nTG%{vB5mDQ^_$o`Qp*+Sy&RST zZi;ME7Y2WRcwnaQ-KSvX1kESpBaVD-PoY_dn?Pr(_`2l&g}v6xqXyzU8b;8#V`r(5 z(WBV2>hEV}d(Czhelu8?u3(P!>#rfjHK z>%eMFCB#{&_`|BE@(G47!&hU&xYzjiDX@1NKx4-D5AV_)lfxhUZv59g3DL6FX%Atf z_xSXqM~PZAIAY(&59!^b#V*|~t}Ud%69Oi-;&hJ-8Ne!Yb`qyUv7Q*N+$0=dlzv0W z9TRdho9C7ulsgVyC0uqXxBS<>}i_GG}heDM}OMHFBkVe z?39$)VN5yasLJm+|Sfc}}%_zS``2Dn9x%U3n1^vSDSMp!i40^6OXDcS{3L&f9 zrL844Ob;2bAeI=1z`N!&DjwXu$3Eq(YMAg6%t$u1vkz%zD`4`{`}e7HGM+oa2V!Q6 z;LC~S#lR9L%3Rv=+w;E<@ich5(z)~FAw$iR_tHe%EY8@~YF7!?b7v()Ranm!<%FtL z^rc1V13tW>(%s4bpOg^SR1YR%Hsi2&>>|As8nIiNBzFs*b`U`$46gtPhM;`;NUY{7 z)?Amo<*Gq{^*3nmt`b&DZrrr+=nV#R;BFu-%H=@!aSIebeh9gzQ1PcnZ>UjzYNr>q zuR!sMTvzpr8%jkE_w)owz9+ZM&apUwO2uy-pDl0=qW63r{;hzyh8s8k%zBi^-SdxP zk|5$;?hU0*<;ya$nu(mF;fDpBGG#>fhyPR06DHlU({+1RI-u~@3rpN*a!Wj3KNQf` zno{s_K@zpfgus2dxa$MmrN9?{f6-I9RYA5zB_(}^fbBvQDq1B+M5t@y7`Oj&fw*GM z8L(2ZbY&Y@s4P1LIJ4v}Tk$y4lHdC*{OGQ}NziCg(L(#&Pm;^HV_nuJzMDG}so(q3 z#ADCD`@d!IKe7P^bzJyY=`xdrf#6j^1Pzha{VM%EB}-BNY1HlLtbL%fRhf5ogB3Y5 z-t!G=VQ*&9`-&xXk@t#GY!JDB>IN9>O_mOG?F?prFl${EDpP0=UPgpWV9J;Dk_!4d zFIuK2Ub=g0bOVY@E_i?*H{cGh%nsi0cJfhG8C=XdQMP;^7hSdltrxVY ze_LaZgJS27I2!*+#8?qttdCA$!dl(zrCr8hZw4J|sxgrFiaFZdK6^N{)=u~KsK=X? z7znMuS@mkQ9ru+B>ocb_g&cIgLO;;N!w^U|0f`yelGFml{>O--pq%-&HG-ZIkv3u^ zc|L^_lzVg}D8#1bZuyQ_01=8K?d04ib>X@6S+St?__%81Im6SdfaWj3c)&`I-OFWm_pG> zX;uF$_N_4LlsI}uPH3^d@y_y7&!1uy<6in+ko^4ok+#P?NRAJVL}#*sMq3cIs?L%L znO5A+tqF%u_n1#j4&MRKDdAmfFF%nOA!t}p%xl@6TN_aj z_X%X$C4ceRNczONO~0TVl>0LJeD0}yI<^Z#ERRPShkoG!kb+^9QlqaYhW$JNpnhb? zaH->oT9ux@WA;>HGL za3>BzvZ# zMl(e$umN^IvO|^i`JA$M_@J_jv}+3$(Coy;K9BK2xRbcqNO87yaD0}wv`KIOh!GNrU((>(jo06Zki&u47V0d*W-l_6M zQ&dh#Ntw+N9!2zSve+pSfMDa01V*++Grp{jS<1d|nQkz5t#tI7hhcId*!Sqb-yq0g zRziMEeX8NK$JJ)KbpMeP)s(B4Kv;%s!Li=JYy}B!xW@qJ>rVb!TG|9R^i256z)cM^ zP<^xFr>s+m`Lsj?99}W%Z*1d>?><*|xyIUHLu@;_?6tp}@)TLcV`oob2^j2EzXV!D~BqhUD4Z*GdWqVX?_uN~0A+$;*BacsA*(PTf#GYmrRW z=!N64b9p4EbdQNboK~(CbsAdY@e6-Blv3(~v%_8|0HnVLf^(}ReMpqI)U&ugd1Hgz zCMPtb1Ml|Mg=^n+wDEEfuj{wa)k!IGSMx!S*NSD3?az}Mzg|wE zKFsN$&1D^A6N0I(W_7%Pw+x@0mvSl|50Lkt0c?%a2$JV2h91bTM8xBR&wbb8 z9QS4WCp{B}rlzhN=3NzOT}ZoOZOG^PC*KtzmEC^GVZ-V#a?)j$Jydm|Orcq8896_VP7aWF7urEu6eC?swxexB~`-SwJtS^@D)f5=HgdGo9UXxCkF3f42t{M+0 zEB#3i{nBn^?80t3sbX|GmFq8)+6hvvw4QluT?7(-NsUD85h`=|!-Er|7GABA%l$}U z{OlzBP9D>X*~?4PZa~0$q_Z_W{Pjqdy{&kLccj5-*AId`;*aoToQ73uCuJdY)xF1C zId;QNsLZ{u@MaNCn;u~>ADM^pE3%;`ymY~R6-y&5%qnqMtZ;MNS>tk?v1NLnAyP8L z@?<9?LIJKINJ8jpTdXSuONX0RHfErT$)i0$f_5wzPbMZ?^S%e+#t&)lZ4E-y?E@ZF z!DYrnU@JP&H0<02hP1*Ab0x;M5U;ir`Whe7H}z4QurCD{4XThG?bS3hXY!9~FwT7bFmtWsl9N^sEj}D(5&{`nzdoE?xdWYZU}2%>m^k4<8_!<~l7VWV#R^-j`?* zQL9?4rwfb(V$r8Yv_HoxMR(P__uFdM(WEjTUj~X=K(yllpa3W)Od3RJ#|_aBaIwb; z7+SK7hPLo$v?Puc_{9z9<2rT7FH9*;E&_pYFSpmym%Wtecc`)n|H4Ev!70<*X`~Jl zYaG|C`EXLa7f>5Ebcb+q2Yt}x6N0)P=}5QM7Fz-|_X=HBrUJscnc0TU7ta8w#;v{U z+lIQxCFCQ*#mAAC^{Y_*q09@F(6(ThQGWR{%!n1|@~vZs1h_;}fud-lX%X1FyqvHw zR7b9OIk(?Ly7T!9-|;n(JkZaH8x_@vkb8#(BJ*TZEwBNel9}EM>7hRwu6_h~aW&p% zDjfa&qfQF`%U0~6yH<7UEh3|C<?X5fDZ}90-e1*@d{aVh~0fLLjn3R3c#5AxIQW5CsC*5S1k= zIEX|@SY?+jX%Zk!AnZ$HfDo3j2?0WqiP|syG*wp3R6q3FU+124?pNPE_dn;m3IDRc zs34~%CnY7NV0-EOH7TiWDN<6~U&?HkSS%fC3#Fv?j@X_*;~1GWKQfZ>`jQ&<>T{>c zXHlsGDz;h^ztDe@IV+>%J|MVB**v)ve^ff}T|9w6C@wBmKg}0KtnHBM*=O(%tmii1 z5Au%=K~L{$-0m%-yyqP0o@(5WEqnf6`kRgKt_@LE-L^b6>^L8t$d2S?+&LK6O6L{C znT1@EkyMuZlxj+;jIwdarC(jLnm_qXDnSn2$birJVlIG{Jv1(pZo_fIB3h@^hMTUDReF~85@ALvtd#I+ig0;B7@epEPl z2zs)jN4LWp)aZ@xxEQ|K`eku-MF10kdFE^tMn9K$Pbm;&|tm|M*x^&MTgTYK>Q8wfT8e~6YpZ$C7&J) ztHJXfv6Yq^JMw=-aFw>|>W0iTbs?}6#9BdiO?*zsr4O5$=*9SZ*4T#5(G)RiI89Mt z2#ZZ+M9bSlz0$|n0>bX*V;kLyg3~0O$t3#%R;PAvTV1Cx06AsLAHXjxQDS3Lo6cW; zU!ixB7faWx;nX~E+AmPMvA;SG!aoQ7ntre7CnKv&YeFj#GiL@F5Dkj#sAK-6# zJ6x&ibDT;JN{Di7$XC*QHRVwG{*39V++}UN*-O$9T&0RBe6?ec*xdXGpB2TdWAVE& zxU0fUNqMmE9OZ~+9ioip)lG^|H*?(0!(qa1Y;vR-j5QO^TxfkW60ib`xy-dU*U8#4 z4U7~8a}m@4ttZ)qSZjWO;A;QkO@XuBMbPh=X1@pA7(i5nFm}|IZRSjm!vrA^=u?k- z5$ZOT3o_?8pT~4GCF85JS%KCi-YNgDoqb` z{FC}g7(|!EN~>PVA=i+(h!g7KXsE@_iACn(qP)Lmmjgv#ZBiK zyWI5l1KDVI5KxD@dXw9;g|F0_GWBS4@$&o+KSO5nfIfx)zc2E18l2XLZD6%2QrMI+gs@ zv)^?7fyuxyQsV~Uo@9d}(+Ur^XGhNc6Y%zDWZgkD_(OHqA1RAMcY14R5_22`2Ts7} zTF456J7>$}2W@U>yUqGaib+aT1zI&8n zr-&Vei(_a^ELRI`0&nkUQNsOeo2tct&rj9AY_KGOE5;Lo#7VOYNzKPjiTX?uCFTM$ zWRTGO;`S$|vbqGezmK5&x|dVnn{N;cej|If?5;SBt-Qm_^6jD_OdIKD~7&OJXGvQ;!(-X z9+g!OU|%y4(!bM$3ViD9UY^I)bO4KR-QWaFOV*;5?nNCuI^y#8HnaRF$zX3PBFsuSvHnsni z&*z^=-i|r$!0>5R&OTz1H9Fp;#^ZohXkx4kqyg@*OC7bM>b93?FXY)53ew2usMAS7 zviDWv((^c_U3~}G=i^xARJXSzt3P7$HH+Ko#YfUOAx2-Ynb}wK5#eIJITR&XH5UN+ zd#L{YqyI|^lPwFBw9NpYAJNgzU@*F1!FmnGHO{NrE?#b(604uBfN#sds6n7RUu>oE zGsV`mOF*=>XJwecUNBB=X*oE8cWE^5Aux3jRL27@5#Qr zMOT;Zx+Kpq-?h+oKA+DN9eZwU7bxJaQc3CjyQ>$=?#3x-Ep8wKOIDSeB_R6x`UWzQ zvguZwIZN-Mq}5C^2MAa|wd^-Ig;!97RyDng@z-dyAlBR2EMX45j9q?2sNbkRYSUPu zxE{&p1S9t}&a^TZ4o}@~Hrtd&$l@pElfQW%A)bC zh2@OPjty`-mr_R?kKKo%ZZKhV5j=PWhvI%k3a?xRI!tI=#Ix{JL@{0Pac*OMGmPeI z5sofXz_~B5JF{#E5S3CoMa+ZwgtRO_y}R@Bc^tcagjvQZpjj;1Ej9q&-In zL-T8^t6^(!DdIN;^nZ}uY{r24M_H`bv*F{(Y&}>>w=m&hAgFjB5fNq2V$X-8EIBEQ zXEXerKvJBNrs~I3RqNusyvH(eVHTy-yKHljDMF$hKF-J%wg5LZ%Dx7Lj)>o8CE`0%uVnb(05!pT49kn! z<(??v?n47;>wUrus*W|tzRHIE;L1>EKDo(z6#J7M6Y|J)Tx{g#>SRu*gvltEXPx~N z8h4>h=Ncxgy9=Zi7#C)OVHa?GfaoR6s7&vX+t35q?tt`(=RvZ@`7uX&)QAQk42QP$fc(%u~=dGJ^v`7y~E*0wOa4NhtV8H3DssK>|`y zK?xy<43YpTMT`;#F(i>dh(bdkhY&Fy0vX^v^iRCc2hW#%oxRUqd#| zo%ik&lap<#B>(^zwbxA!qf@y1p47VBf>-IlLJX_xYr`W6dK(F>%Hn$d;wzZ(Q&!c^ z;CerS^~pw}C899NGoZq+jF;b9-?zAt&>MIw*)v*P6l1`aNXVBGfAc!27wta4<@)Ep zXwi+7{g$_pV0En3E~=#hWu1$9(6ut#7LlsTupq#4`*cjZiLY@c-v2?*x6^86UWsFS z$t8%2&9E#Lnp|bh-T|?k{XN65?GNLre0jcKum;qTynqZqHOs9^+FXg4uIo zK1cLj&y+r6G)n%XcE0$BSHBm1z@VClHpEBX26 zo+3NP`*^IL`^toNIN|(PGR$zyz&K^?pQVSp(YqVD} zvusz>Pu7PG!ykG#&CZr5kEufpO+A`srv~g_M#G>T@uo?P^5asJ);EwN{6?RJt1*RJ z?$0?l*}Q+R@XaSw#~Z&b2zx4dg$z5lFYT@SY36rGRoOP3_4wRBV!j?9N8B=HV_?^m zYi=J7$w9PEWvmBy5@FA?y%{z#`%u|hEv{5{%P5D?EiwI!yMvbvg2~awXu~&e8}!C5 z?{O#F%&yD#=8quA_PwhZ9uC-h&ZKZZ+VIiFM~;sCww;e|O^+S?XCu6b5SX|l7F{`0 zex5wd&@$eRpxPJ*okd0EqSC?7Eewx`|3>QIO{1_n`~Rg9u(lKyZ$%uuBx|pmT2s~E z`~~x`$EGo@frBC$`||nKaj9H8?*v_tkf~xanGiz;2M1*`*+uh}`%gT}%Zmp@GGS5x zEQ>BMBXn^AwPa2a>qk1jGBpQg1|`r-F<26`zB(e6Kf_dv#VwUcr>Cb^S8-C^C8fHk zsEB`p1Ei|M0Z<__R;GIoEFLa)W6|(G?4A#qU)%Ix&%HZerV<1P8`>V;8i}^pt$Ss4%%S1vl0w0g${Ev%*mq-bekYf{wd#Q^v;>j; z^!4>YUr?!5DwUy>_CRteGZG|0Y#6+BoH)4p_D)i2jkOLEi6rfrlPjyMtAq5>2pH)2 z)e&MKJsA7D-ljZ$pHr1LU~+SgxWBI1Z5i8ats|J6tjFWCv*#E3I_Y!@zKc$$uf4ew zLaD2(6F0q#w&2m;F{T$Io<4Ru2%ZnKaalSX4!-W7(-Z7wlJIz>LBZ0(hkCsurCLE* z+SS7%sZ>g0*Bh=G6fuO!Xk12e^6}leVx^KKc>~?seCSiLIRC*&wDh5sm#1j^z2k5% zE20;82+BxM8>mpPrr2S#vm0*kc>4quJqi!ob^Cp^S2geAtYj*T=(zb2)6)izHWf)wy7Cjukbls3*&66a2}RPuhZ zF1Dh4=zv3%X~n3VvNw5Klfhcp5AW2H6ubDNeHjjuSk+y^6abKpRAgDl>FZgppMTLN zx%lH~ok>OLY;!~0j@7T(CcbG;F;@qe!Xz6*Ka4UJf{u$5_o~f=@|9dJZx$!kpL5Ch zz2h;7Qf@&m=3rIRD=XIke;*$okjy-mkdOf7^4JBZ)H88bL>i5zaJo)S@=Q*TfY9ID z`x9&3K?p~=B1IaGS_)SPg~Dc|0y-jdYwT0>s3_8|>YhaglgsDegky1SXoQoKQ-3=~ zJx{B(Y%srpqa*Kn_UE@{QX>Ep^?L)(lYjm7EfUZ+rF1IVF4~@HY_Lbb2#V4<4pCN# zIx`#_unPhVyXNsJnx!u`qQ9^M%v7(e1Q>}Sa>PC!ibeD9EdaxC>O2}@mU4}%NMLcB zn)5&qY*n%y4GL;mF-!y8qdERL!N)P|FYRd)7GD9E1Zk(4<@%d|(e*rMv4^iXg0yfC z@O9kUa=f}tR`Yl`PFeF9ZwT!MWqgT1Q6}WPorN_F`S`DGo*&{f7>p-opA%q44HP71 zj*6qNsZ^b4M8&4KOt~+xJxku1t?nqhe+ZrRV5}ubR327k@ptk}1V!O?P(+XC0AQTe zIPF}m`!MIIj|er=Z9;aMQB+(w&#q;^zP#bee_Ml^?2sYgNhukxb}P!hkAF6gMMEH1 zRjDRI*nwm}3WWkC3VOVh?rH4dtT>)}?6ZuTr+ ziouY|@HU2xTp*9M32gUZ<|)-U<tz)LvbJgv%>9fMwJ~@2OX3 zL?&M9u}6kz`J2Z1*h`=;!xB zszeSfVeS~-vw~UdwS9-BF2NOclLOY=_8YCS4*SXyJ`ssTh$?wyFn?gXB%uehiUqxr zf84Fx|A)h;(R-K2JG1e=NQxljLFF|}nn#ImS65faM=O1iAnh{XJRSWIG9H+y~UH+}y4?k**m*$uNV(@> zL6^t#?(Yi)td`WT$A!kgNgsbRZc@j@_+TuxIR4||50{=@Q@AMMIQ71V+AcwOnuTQV zni_rv&k7zb0$L|@Nf}rydEaSdb10^r7er#>sD%N$WGgC&6c8;k|Kfo6;g$EgAcSH6 zs_n4P*ml76YLnRPJQMZ;I!0+4cc!ZkQr|RzBU5NTwWKAmfU~Vq$Mo5|%AmlAYi|lQ zr>Co@ri_{tHSg?uAnhtH5JDF8+Ot;-$z|Y6>52xYT zD|2GZej5B+NP$ALudRB`MNt#tg(YUPk?0nhISBF9GL9L;kXXO29K570<-AF;#j#>0 zw1-oWsnoq8}lJPg%otK9yT$61sO zioxy#)BbN}vdkz);QJc5K&@6N#6RGrF3L7_VL&I=yvkc1DmlGlZ1j!!=wvzgoAiX<8c1O#Kh30XT@p1t|oyVB(d^<*}}p?ZEDh zwe3jbF*I^!X{k+hAag?~Blx3qJKb%0uOEpGK?%R66x2RDBsSit;sLIW7fj#l&)M_o zKVkE^9DX+!NX52Cv+nT(@9kzZ#c?|p+EbYyyWsNAN;Rh2MFveCwbGG~Q^)0EBeqX} zVk2hNmR{JAbIY>9O1MLy*h=ij5NtnDmeo7BKfH=Yd3{XgD$Kehk> literal 3509 zcmeHK`&SZ%9>+2$Lo{8e`AV}q4K`<__&{uGOSjM!X(*B5lz8-F+@{CR1oE|e`2Sz(~sZJ`JV6l`}v-4;g8`*%*}S0 z0RRB=u+Wg>0D#FY0ASPot(%O9U&OOoBc2r&^6iQA%DGWIWju7#p*MsFjnax)%v&%xiY3ll357FSA|W4}f;#c>ClimqB)!^J&E5@)K$Mc;G~I&~*7U%~KTOL*f@ zNllmLcW8yrpS{2%12bu`$&qdz?kpy{y7~w8tMbJ9s)YLU)js5))LbSz^3>NhJ%rn* zf}ltDPG`13+=#^ePYd8y@agXU#Mg;l3{Se~Axmppf#byABzgw(q+<)hqs938!i2?< ziKB|cDH*YxFeuiP;Vz4+W#1t~Bep>&fR7)9%(~#Rnkbo?v?h#6d32{6!^@Phg`xNu zReCmM2WTwX4X5ua*P&#j6gKT}l&m1|dV;4ySw~W7uqp+1Uv#%M{JXm3(zZZ|8x9=P z2j`FD=psR*6QVp>;=-rcGN{JLIPs3DsV%Yjx zO>SYR*))s5cM)f9BrJ};G(4YHB~|SE7QuL?%?)zK3V66 zL#;Ft**jI+p!Np?yISH z5swB{n&`}EkJEt6O3lI#I}#>T>5AhcH#%x?B{EEXQUU{|27x=(#NAO{vx8c+S^Rn^`Dm0v|D90n`x zV=`WTd>%Pxr}q!&87ePIoxOw;^uxUSrNKAW{m$hQc)(ed&80E+6I!Gr)ioJAHa(9( zsAC*tlK8~g&PDrP8YHljnUS-6qN6pA8y_L92W7G#lX55W)cD%v+rTJ(>H-&$nmM_E z@e}OG!8}W-ew#H$KELXMUOt!2$2tmIFZcUu%2oz+gQ}*yKd8m)$uR>idAWR6*Q{W} zvmr(7t<)8LgSd^Fk&Y|`yH!bSeDORd!|_pvr_*K55bj)Bt>2}Eg60i54VI--YqO=o zg2iy>)hF%4Lv#&USE)PH0xA2otp$U0mwBXXsFX#YQP}c_ljzPuro=1Uw$1~Q>kHZ! zt5msB@(eN`J2`2PNq& znW%L3uH_dIDplo|I3$cqjmv6!C=ch_>m{mJsTCe(zpIHf)s-|Lsujl{gyrTfktyA5x<>U&^vx<+>blu{vQB?eY*bVi(lH3S zR){aa3wA{1_z+)bkyc&aa$npFPcOaL6Sj!qHmvPLKhg?ccLItNql)g8#OU>%?o{Pi!O4y3?R-|%igr*aJ#H)z zca=<$ZX@B4c-Aq{qYLTRPCJvcXd zBVlo2#@!hnYT@Km_7jJnZl*19f3NHi7THPYcN7h1wK>xXg*qUNDQ(}44oF`WgUNT6 xp85r(H~MI bool: - pk: VerifyingKey = VerifyingKey.from_string( - public_key, curve=SECP256k1, hashfunc=sha256 - ) - return pk.verify( - signature=signature, data=message, hashfunc=keccak_256, sigdecode=sigdecode_der - ) +# def check_signature_validity( +# public_key: bytes, signature: bytes, message: bytes +# ) -> bool: +# pk: VerifyingKey = VerifyingKey.from_string( +# public_key, curve=SECP256k1, hashfunc=sha256 +# ) +# return pk.verify( +# signature=signature, data=message, hashfunc=keccak_256, sigdecode=sigdecode_der +# ) From 0194144a50d9bd7253ce591af8e8974c59b768c5 Mon Sep 17 00:00:00 2001 From: Christopher Tarry Date: Tue, 14 Nov 2023 14:42:40 -0500 Subject: [PATCH 03/16] get back button working on Stax --- src/calcTxnHash_nbgl.c | 149 ++++++++++++++++++++++------------------- src/sia_ux.h | 5 +- src/txn.c | 23 ++----- src/txn.h | 8 +-- tests/requirements.txt | 1 - 5 files changed, 89 insertions(+), 97 deletions(-) diff --git a/src/calcTxnHash_nbgl.c b/src/calcTxnHash_nbgl.c index 6901525..a5efacc 100644 --- a/src/calcTxnHash_nbgl.c +++ b/src/calcTxnHash_nbgl.c @@ -14,18 +14,31 @@ static calcTxnHashContext_t *ctx = &global.calcTxnHashContext; -static void fmtTxnElem(void); +static void fmtTxnElem(); static bool nav_callback(uint8_t page, nbgl_pageContent_t *content); static void confirm_callback(bool confirm); +static uint16_t display_index() { + txn_state_t *txn = &ctx->txn; + uint16_t first_index_of_type = 0; + const txnElemType_e current_type = txn->elements[ctx->elementIndex].elemType; + for (uint16_t i = 0; i < txn->elementIndex; i++) { + if (current_type == txn->elements[i].elemType) { + first_index_of_type = i; + break; + } + } + return ctx->elementIndex - first_index_of_type + 1; +} + // This is a helper function that prepares an element of the transaction for // display. It stores the type of the element in labelStr, and a human- // readable representation of the element in fullStr. As in previous screens, // partialStr holds the visible portion of fullStr. -static void fmtTxnElem(void) { +static void fmtTxnElem() { txn_state_t *txn = &ctx->txn; - switch (txn->elements[txn->elementIndex - 1].elemType) { + switch (txn->elements[ctx->elementIndex].elemType) { case TXN_ELEM_SC_OUTPUT: memmove(ctx->labelStr, "SC Output #", 11); bin2dec(ctx->labelStr + 11, display_index(txn)); @@ -33,36 +46,25 @@ static void fmtTxnElem(void) { // user needs to see both the destination address and the amount. // These are rendered in separate screens, and elemPart is used to // identify which screen is being viewed. - if (ctx->elemPart == 0) { - memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outAddr, sizeof(txn->elements[txn->elementIndex - 1].outAddr)); - ctx->elemPart++; - } else { - memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outVal, sizeof(txn->elements[txn->elementIndex - 1].outVal)); - formatSC(ctx->fullStr, txn->elements[txn->elementIndex - 1].valLen); - ctx->elemPart = 0; - } + memmove(ctx->fullStr[0], txn->elements[ctx->elementIndex].outAddr, sizeof(txn->elements[ctx->elementIndex].outAddr)); + memmove(ctx->fullStr[1], txn->elements[ctx->elementIndex].outVal, sizeof(txn->elements[ctx->elementIndex].outVal)); + formatSC(ctx->fullStr[1], txn->elements[ctx->elementIndex].valLen); break; case TXN_ELEM_SF_OUTPUT: memmove(ctx->labelStr, "SF Output #", 11); bin2dec(ctx->labelStr + 11, display_index(txn)); - if (ctx->elemPart == 0) { - memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outAddr, sizeof(txn->elements[txn->elementIndex - 1].outAddr)); - ctx->elemPart++; - } else { - memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outVal, sizeof(txn->elements[txn->elementIndex - 1].outVal)); - memmove(ctx->fullStr + txn->elements[txn->elementIndex - 1].valLen, " SF", 4); - ctx->elemPart = 0; - } + memmove(ctx->fullStr[0], txn->elements[ctx->elementIndex].outAddr, sizeof(txn->elements[ctx->elementIndex].outAddr)); + memmove(ctx->fullStr[1], txn->elements[ctx->elementIndex].outVal, sizeof(txn->elements[ctx->elementIndex].outVal)); + memmove(ctx->fullStr[1] + txn->elements[ctx->elementIndex].valLen, " SF", 4); break; case TXN_ELEM_MINER_FEE: // Miner fees only have one part. memmove(ctx->labelStr, "Miner Fee #", 11); bin2dec(ctx->labelStr + 11, display_index(txn)); - memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outVal, sizeof(txn->elements[txn->elementIndex - 1].outVal)); - formatSC(ctx->fullStr, txn->elements[txn->elementIndex - 1].valLen); - ctx->elemPart = 0; + memmove(ctx->fullStr[0], txn->elements[ctx->elementIndex].outVal, sizeof(txn->elements[ctx->elementIndex].outVal)); + formatSC(ctx->fullStr[0], txn->elements[ctx->elementIndex].valLen); break; default: @@ -96,61 +98,57 @@ static void confirm_callback(bool confirm) { } } -static nbgl_layoutTagValue_t pair; +static nbgl_layoutTagValue_t pairs[3]; static bool nav_callback(uint8_t page, nbgl_pageContent_t *content) { UNUSED(page); - if (ctx->elemPart > 0) { - fmtTxnElem(); - } else { - // Attempt to decode the next element of the transaction. Note that this - // code is essentially identical to ui_calcTxnHash_elem_button. Sadly, - // there doesn't seem to be a clean way to avoid this duplication. - switch (txn_next_elem(&ctx->txn)) { - case TXN_STATE_ERR: - io_exchange_with_code(SW_INVALID_PARAM, 0); - return false; - break; - case TXN_STATE_PARTIAL: - io_exchange_with_code(SW_OK, 0); - return false; - break; - case TXN_STATE_READY: - ctx->elemPart = 0; - fmtTxnElem(); - break; - case TXN_STATE_FINISHED: - ctx->finished = true; - - content->type = INFO_LONG_PRESS; - content->infoLongPress.icon = &C_stax_app_sia; - if (ctx->sign) { - memmove(ctx->fullStr, "with key #", 10); - bin2dec(ctx->fullStr + 10, ctx->keyIndex); - memmove(ctx->fullStr + 10 + (bin2dec(ctx->fullStr + 10, ctx->keyIndex)), "?", 2); - - content->infoLongPress.text = "Sign Transaction"; - content->infoLongPress.longPressText = ctx->fullStr; - } else { - memmove(G_io_apdu_buffer, ctx->txn.sigHash, 32); - io_exchange_with_code(SW_OK, 32); - bin2hex(ctx->fullStr, ctx->txn.sigHash, sizeof(ctx->txn.sigHash)); - - content->infoLongPress.text = ctx->fullStr; - content->infoLongPress.longPressText = "Confirm Hash"; - } - return true; - break; + ctx->elementIndex = page; + if (ctx->elementIndex >= ctx->txn.elementIndex) { + ctx->finished = true; + + content->type = INFO_LONG_PRESS; + content->infoLongPress.icon = &C_stax_app_sia; + if (ctx->sign) { + memmove(ctx->fullStr[0], "with key #", 10); + bin2dec(ctx->fullStr[0] + 10, ctx->keyIndex); + memmove(ctx->fullStr[0] + 10 + (bin2dec(ctx->fullStr[0] + 10, ctx->keyIndex)), "?", 2); + + content->infoLongPress.text = "Sign Transaction"; + content->infoLongPress.longPressText = ctx->fullStr[0]; + } else { + memmove(G_io_apdu_buffer, ctx->txn.sigHash, 32); + io_exchange_with_code(SW_OK, 32); + bin2hex(ctx->fullStr[0], ctx->txn.sigHash, sizeof(ctx->txn.sigHash)); + + content->infoLongPress.text = ctx->fullStr[0]; + content->infoLongPress.longPressText = "Confirm Hash"; } + return true; } - pair.item = ctx->labelStr; - pair.value = ctx->fullStr; + fmtTxnElem(); + + pairs[0].item = "Label"; + pairs[0].value = ctx->labelStr; + + if (ctx->txn.elements[ctx->elementIndex].elemType == TXN_ELEM_MINER_FEE) { + pairs[1].item = "Value"; + pairs[1].value = ctx->fullStr[0]; + + content->tagValueList.nbPairs = 2; + content->tagValueList.pairs = &pairs; + } else { + pairs[1].item = "Address"; + pairs[1].value = ctx->fullStr[0]; + pairs[2].item = "Value"; + pairs[2].value = ctx->fullStr[1]; + + content->tagValueList.nbPairs = 3; + content->tagValueList.pairs = &pairs; + } - content->type = TAG_VALUE_LIST; content->title = NULL; - content->tagValueList.nbPairs = 1; - content->tagValueList.pairs = &pair; + content->type = TAG_VALUE_LIST; content->tagValueList.callback = NULL; content->tagValueList.startIndex = 0; @@ -180,6 +178,7 @@ void handleCalcTxnHash(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dat if (prev_initialized) { THROW(SW_IMPROPER_INIT); } + ctx->elementIndex = 0; ctx->finished = false; ctx->initialized = true; @@ -213,7 +212,17 @@ void handleCalcTxnHash(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dat txn_update(&ctx->txn, dataBuffer, dataLength); *flags |= IO_ASYNCH_REPLY; - nbgl_useCaseRegularReview(0, 0, "Cancel", NULL, nav_callback, confirm_callback); + switch (txn_parse(&ctx->txn)) { + case TXN_STATE_ERR: + io_exchange_with_code(SW_INVALID_PARAM, 0); + break; + case TXN_STATE_PARTIAL: + io_exchange_with_code(SW_OK, 0); + break; + case TXN_STATE_FINISHED: + nbgl_useCaseRegularReview(0, 0, "Cancel", NULL, nav_callback, confirm_callback); + break; + } } #endif /* HAVE_BAGL */ \ No newline at end of file diff --git a/src/sia_ux.h b/src/sia_ux.h index 426ad7e..9373c38 100644 --- a/src/sia_ux.h +++ b/src/sia_ux.h @@ -37,10 +37,13 @@ typedef struct { uint32_t keyIndex; bool sign; uint8_t elemPart; // screen index of elements + + uint16_t elementIndex; + txn_state_t txn; // NULL-terminated strings for display char labelStr[40]; // variable length - char fullStr[128]; // variable length + char fullStr[2][128]; // variable length bool initialized; // protects against certain attacks bool finished; // whether we have reached the end of the transaction } calcTxnHashContext_t; diff --git a/src/txn.c b/src/txn.c index fa708f5..05d87e8 100644 --- a/src/txn.c +++ b/src/txn.c @@ -191,18 +191,6 @@ static void addReplayProtection(cx_blake2b_t *S) { blake2b_update(S, replayPrefix, 1); } -uint16_t display_index(txn_state_t *txn) { - uint16_t first_index_of_type = 0; - const txnElemType_e current_type = txn->elements[txn->elementIndex - 1].elemType; - for (uint16_t i = 0; i < txn->elementIndex; i++) { - if (current_type == txn->elements[i].elemType) { - first_index_of_type = i; - break; - } - } - return txn->elementIndex - first_index_of_type; -} - // throws txnDecoderState_e static void __txn_next_elem(txn_state_t *txn) { // too many elements @@ -244,8 +232,7 @@ static void __txn_next_elem(txn_state_t *txn) { txn->sliceIndex++; txn->elements[txn->elementIndex + 1].elemType = txn->elements[txn->elementIndex].elemType; txn->elementIndex++; - - THROW(TXN_STATE_READY); + return; case TXN_ELEM_SF_OUTPUT: readCurrency(txn, txn->elements[txn->elementIndex].outVal); // Value @@ -256,8 +243,7 @@ static void __txn_next_elem(txn_state_t *txn) { txn->sliceIndex++; txn->elements[txn->elementIndex + 1].elemType = txn->elements[txn->elementIndex].elemType; txn->elementIndex++; - - THROW(TXN_STATE_READY); + return; case TXN_ELEM_MINER_FEE: readCurrency(txn, txn->elements[txn->elementIndex].outVal); // Value @@ -267,8 +253,7 @@ static void __txn_next_elem(txn_state_t *txn) { txn->sliceIndex++; txn->elements[txn->elementIndex + 1].elemType = txn->elements[txn->elementIndex].elemType; txn->elementIndex++; - - THROW(TXN_STATE_READY); + return; // these elements should be decoded, but not displayed case TXN_ELEM_SC_INPUT: @@ -310,7 +295,7 @@ static void __txn_next_elem(txn_state_t *txn) { } } -txnDecoderState_e txn_next_elem(txn_state_t *txn) { +txnDecoderState_e txn_parse(txn_state_t *txn) { // Like many transaction decoders, we use exceptions to jump out of deep // call stacks when we encounter an error. There are two important rules // for Ledger exceptions: declare modified variables as volatile, and do diff --git a/src/txn.h b/src/txn.h index e7ab909..c7ef756 100644 --- a/src/txn.h +++ b/src/txn.h @@ -71,15 +71,11 @@ void txn_init(txn_state_t *txn, uint16_t sigIndex, uint32_t changeIndex); // txn_update adds data to a transaction decoder. void txn_update(txn_state_t *txn, uint8_t *in, uint8_t inlen); -// txn_next_elem decodes the next element of the transaction. If the element +// txn_parse decodes the the transaction. If elements // is ready for display, txn_next_elem returns TXN_STATE_READY. If more data // is required, it returns TXN_STATE_PARTIAL. If a decoding error is // encountered, it returns TXN_STATE_ERR. If the transaction has been fully // decoded, it returns TXN_STATE_FINISHED. -txnDecoderState_e txn_next_elem(txn_state_t *txn); - -// display_index returns the current display index for UI purposes based -// on the current elementIndex. -uint16_t display_index(txn_state_t *txn); +txnDecoderState_e txn_parse(txn_state_t *txn); #endif /* TXN_H */ \ No newline at end of file diff --git a/tests/requirements.txt b/tests/requirements.txt index 54ff69f..d2da92c 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -4,4 +4,3 @@ ragger[ledgerwallet]>=1.6.0 Jinja2==3.1.2 Flask==2.1.2 ecdsa>=0.16.1,<0.17.0 -pysha3>=1.0.0,<2.0.0 From e4e4562511e089ac36d95b4ffc935d8861b80464 Mon Sep 17 00:00:00 2001 From: Christopher Tarry Date: Tue, 14 Nov 2023 15:51:28 -0500 Subject: [PATCH 04/16] prefetch transaction on non stax devices --- src/calcTxnHash.c | 299 +++++++++++++++++++---------------------- src/calcTxnHash_nbgl.c | 14 +- src/txn.h | 1 - 3 files changed, 149 insertions(+), 165 deletions(-) diff --git a/src/calcTxnHash.c b/src/calcTxnHash.c index 1ba9163..46f4248 100644 --- a/src/calcTxnHash.c +++ b/src/calcTxnHash.c @@ -35,6 +35,7 @@ static calcTxnHashContext_t *ctx = &global.calcTxnHashContext; static void fmtTxnElem(void); +static uint16_t display_index(void); static unsigned int ui_calcTxnHash_elem_button(void); static unsigned int io_seproxyhal_touch_txn_hash_ok(void); @@ -43,7 +44,7 @@ UX_STEP_CB( bnnn_paging, ui_idle(), {"Compare Hash:", - global.calcTxnHashContext.fullStr}); + global.calcTxnHashContext.fullStr[0]}); UX_FLOW( ux_compare_hash_flow, @@ -53,7 +54,7 @@ UX_STEP_NOCB( ux_sign_txn_flow_1_step, nn, {"Sign this txn", - global.calcTxnHashContext.fullStr}); + global.calcTxnHashContext.fullStr[0]}); UX_STEP_VALID( ux_sign_txn_flow_2_step, @@ -86,7 +87,7 @@ UX_STEP_CB( bnnn_paging, ui_calcTxnHash_elem_button(), {global.calcTxnHashContext.labelStr, - global.calcTxnHashContext.fullStr}); + global.calcTxnHashContext.fullStr[0]}); // For each element of the transaction (sc outputs, sf outputs, miner fees), // we show the data paginated for confirmation purposes. When the user @@ -103,101 +104,97 @@ static unsigned int io_seproxyhal_touch_txn_hash_ok(void) { } static unsigned int ui_calcTxnHash_elem_button(void) { - if (ctx->elemPart > 0) { - // We're in the middle of displaying a multi-part element; display - // the next part. - fmtTxnElem(); - ux_flow_init(0, ux_show_txn_elem_flow, NULL); + if (ctx->elementIndex >= ctx->txn.elementIndex) { + // We've finished decoding the transaction, and all elements have + // been displayed. + if (ctx->sign) { + // If we're signing the transaction, prepare and display the + // approval screen. + memmove(ctx->fullStr[0], "with key #", 10); + memmove(ctx->fullStr[0] + 10 + (bin2dec(ctx->fullStr[0] + 10, ctx->keyIndex)), "?", 2); + ux_flow_init(0, ux_sign_txn_flow, NULL); + } else { + // If we're just computing the hash, send it immediately and + // display the comparison screen + memmove(G_io_apdu_buffer, ctx->txn.sigHash, 32); + io_exchange_with_code(SW_OK, 32); + bin2hex(ctx->fullStr[0], ctx->txn.sigHash, sizeof(ctx->txn.sigHash)); + ux_flow_init(0, ux_compare_hash_flow, NULL); + } + // Reset the initialization state. + ctx->elementIndex = 0; + ctx->initialized = false; return 0; } - // Attempt to decode the next element in the transaction. - switch (txn_next_elem(&ctx->txn)) { - case TXN_STATE_ERR: - // The transaction is invalid. - io_exchange_with_code(SW_INVALID_PARAM, 0); - ui_idle(); - break; - case TXN_STATE_PARTIAL: - // We don't have enough data to decode the next element; send an - // OK code to request more. - io_exchange_with_code(SW_OK, 0); - break; - case TXN_STATE_READY: - // We successively decoded one or more elements; display the first - // part of the first element. - ctx->elemPart = 0; - fmtTxnElem(); - ux_flow_init(0, ux_show_txn_elem_flow, NULL); - break; - case TXN_STATE_FINISHED: - // We've finished decoding the transaction, and all elements have - // been displayed. - if (ctx->sign) { - // If we're signing the transaction, prepare and display the - // approval screen. - memmove(ctx->fullStr, "with key #", 10); - memmove(ctx->fullStr + 10 + (bin2dec(ctx->fullStr + 10, ctx->keyIndex)), "?", 2); - ux_flow_init(0, ux_sign_txn_flow, NULL); - } else { - // If we're just computing the hash, send it immediately and - // display the comparison screen - memmove(G_io_apdu_buffer, ctx->txn.sigHash, 32); - io_exchange_with_code(SW_OK, 32); - bin2hex(ctx->fullStr, ctx->txn.sigHash, sizeof(ctx->txn.sigHash)); - ux_flow_init(0, ux_compare_hash_flow, NULL); - } - // Reset the initialization state. - ctx->initialized = false; - break; - } + + fmtTxnElem(); + ux_flow_init(0, ux_show_txn_elem_flow, NULL); return 0; } +// Gets the current index number to be displayed in the UI +static uint16_t display_index(void) { + txn_state_t *txn = &ctx->txn; + uint16_t first_index_of_type = 0; + const txnElemType_e current_type = txn->elements[ctx->elementIndex].elemType; + for (uint16_t i = 0; i < txn->elementIndex; i++) { + if (current_type == txn->elements[i].elemType) { + first_index_of_type = i; + break; + } + } + return ctx->elementIndex - first_index_of_type + 1; +} // This is a helper function that prepares an element of the transaction for // display. It stores the type of the element in labelStr, and a human- // readable representation of the element in fullStr. As in previous screens, // partialStr holds the visible portion of fullStr. -static void fmtTxnElem() { +static void fmtTxnElem(void) { txn_state_t *txn = &ctx->txn; - switch (txn->elements[txn->elementIndex - 1].elemType) { + switch (txn->elements[ctx->elementIndex].elemType) { case TXN_ELEM_SC_OUTPUT: { memmove(ctx->labelStr, "SC Output #", 11); - bin2dec(ctx->labelStr + 11, display_index(txn)); + bin2dec(ctx->labelStr + 11, display_index()); // An element can have multiple screens. For each siacoin output, the // user needs to see both the destination address and the amount. // These are rendered in separate screens, and elemPart is used to // identify which screen is being viewed. if (ctx->elemPart == 0) { - memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outAddr, sizeof(txn->elements[txn->elementIndex - 1].outAddr)); + memmove(ctx->fullStr[0], txn->elements[ctx->elementIndex].outAddr, sizeof(txn->elements[ctx->elementIndex].outAddr)); ctx->elemPart++; } else { - memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outVal, sizeof(txn->elements[txn->elementIndex - 1].outVal)); - formatSC(ctx->fullStr, txn->elements[txn->elementIndex - 1].valLen); + memmove(ctx->fullStr[0], txn->elements[ctx->elementIndex].outVal, sizeof(txn->elements[ctx->elementIndex].outVal)); + formatSC(ctx->fullStr[0], txn->elements[ctx->elementIndex].valLen); ctx->elemPart = 0; + + ctx->elementIndex++; } break; } case TXN_ELEM_SF_OUTPUT: { memmove(ctx->labelStr, "SF Output #", 11); - bin2dec(ctx->labelStr + 11, display_index(txn)); + bin2dec(ctx->labelStr + 11, display_index()); if (ctx->elemPart == 0) { - memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outAddr, sizeof(txn->elements[txn->elementIndex - 1].outAddr)); + memmove(ctx->fullStr[0], txn->elements[ctx->elementIndex].outAddr, sizeof(txn->elements[ctx->elementIndex].outAddr)); ctx->elemPart++; } else { - memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outVal, sizeof(txn->elements[txn->elementIndex - 1].outVal)); - memmove(ctx->fullStr + txn->elements[txn->elementIndex - 1].valLen, " SF", 4); + memmove(ctx->fullStr[0], txn->elements[ctx->elementIndex].outVal, sizeof(txn->elements[ctx->elementIndex].outVal)); + memmove(ctx->fullStr[0] + txn->elements[ctx->elementIndex].valLen, " SF", 4); ctx->elemPart = 0; + + ctx->elementIndex++; } break; } case TXN_ELEM_MINER_FEE: { // Miner fees only have one part. memmove(ctx->labelStr, "Miner Fee #", 11); - bin2dec(ctx->labelStr + 11, display_index(txn)); - memmove(ctx->fullStr, txn->elements[txn->elementIndex - 1].outVal, sizeof(txn->elements[txn->elementIndex - 1].outVal)); - formatSC(ctx->fullStr, txn->elements[txn->elementIndex - 1].valLen); + bin2dec(ctx->labelStr + 11, display_index()); + memmove(ctx->fullStr[0], txn->elements[ctx->elementIndex].outVal, sizeof(txn->elements[ctx->elementIndex].outVal)); + formatSC(ctx->fullStr[0], txn->elements[ctx->elementIndex].valLen); ctx->elemPart = 0; + ctx->elementIndex++; break; } default: { @@ -261,116 +258,102 @@ void handleCalcTxnHash(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dat // Attempt to decode the next element of the transaction. Note that this // code is essentially identical to ui_calcTxnHash_elem_button. Sadly, // there doesn't seem to be a clean way to avoid this duplication. - switch (txn_next_elem(&ctx->txn)) { + switch (txn_parse(&ctx->txn)) { case TXN_STATE_ERR: THROW(SW_INVALID_PARAM); break; case TXN_STATE_PARTIAL: THROW(SW_OK); break; - case TXN_STATE_READY: + case TXN_STATE_FINISHED: ctx->elemPart = 0; fmtTxnElem(); - ux_flow_init(0, ux_show_txn_elem_flow, NULL); *flags |= IO_ASYNCH_REPLY; - break; - case TXN_STATE_FINISHED: - if (ctx->sign) { - memmove(ctx->fullStr, "with key #", 10); - bin2dec(ctx->fullStr + 10, ctx->keyIndex); - memmove(ctx->fullStr + 10 + (bin2dec(ctx->fullStr + 10, ctx->keyIndex)), "?", 2); - ux_flow_init(0, ux_sign_txn_flow, NULL); - - *flags |= IO_ASYNCH_REPLY; - } else { - memmove(G_io_apdu_buffer, ctx->txn.sigHash, 32); - io_exchange_with_code(SW_OK, 32); - bin2hex(ctx->fullStr, ctx->txn.sigHash, sizeof(ctx->txn.sigHash)); - ux_flow_init(0, ux_compare_hash_flow, NULL); - // The above code does something strange: it calls io_exchange - // directly from the command handler. You might wonder: why not - // just prepare the APDU buffer and let sia_main call io_exchange? - // The answer, surprisingly, is that we also need to call - // UX_DISPLAY, and UX_DISPLAY affects io_exchange in subtle ways. - // To understand why, we'll need to dive deep into the Nano S - // firmware. I recommend that you don't skip this section, even - // though it's lengthy, because it will save you a lot of - // frustration when you go "off the beaten path" in your own app. - // - // Recall that the Nano S has two chips. Your app (and the Ledger - // OS, BOLOS) runs on the Secure Element. The SE is completely - // self-contained; it doesn't talk to the outside world at all. It - // only talks to the other chip, the MCU. The MCU is what - // processes button presses, renders things on screen, and - // exchanges APDU packets with the computer. The communication - // layer between the SE and the MCU is called SEPROXYHAL. There - // are some nice diagrams in the "Hardware Architecture" section - // of Ledger's docs that will help you visualize all this. - // - // The SEPROXYHAL protocol, like any communication protocol, - // specifies exactly when each party is allowed to talk. - // Communication happens in a loop: first the MCU sends an Event, - // then the SE replies with zero or more Commands, and finally the - // SE sends a Status to indicate that it has finished processing - // the Event, completing one iteration: - // - // Event -> Commands -> Status -> Event -> Commands -> ... - // - // For our purposes, an "Event" is a request APDU, and a "Command" - // is a response APDU. (There are other types of Events and - // Commands, such as button presses, but they aren't relevant - // here.) As for the Status, there is a "General" Status and a - // "Display" Status. A General Status tells the MCU to send the - // response APDU, and a Display Status tells it to render an - // element on the screen. Remember, it's "zero or more Commands," - // so it's legal to send just a Status without any Commands. - // - // You may have some picture of the problem now. Imagine we - // prepare the APDU buffer, then call UX_DISPLAY, and then let - // sia_main send the APDU with io_exchange. What happens at the - // SEPROXYHAL layer? First, UX_DISPLAY will send a Display Status. - // Then, io_exchange will send a Command and a General Status. But - // no Event was processed between the two Statuses! This causes - // SEPROXYHAL to freak out and crash, forcing you to reboot your - // Nano S. - // - // So why does calling io_exchange before UX_DISPLAY fix the - // problem? Won't we just end up sending two Statuses again? The - // secret is that io_exchange_with_code uses the - // IO_RETURN_AFTER_TX flag. Previously, the only thing we needed - // to know about IO_RETURN_AFTER_TX is that it sends a response - // APDU without waiting for the next request APDU. But it has one - // other important property: it tells io_exchange not to send a - // Status! So the only Status we send comes from UX_DISPLAY. This - // preserves the ordering required by SEPROXYHAL. - // - // Lastly: what if we prepare the APDU buffer in the handler, but - // with the IO_RETURN_AFTER_TX flag set? Will that work? - // Unfortunately not. io_exchange won't send a status, but it - // *will* send a Command containing the APDU, so we still end up - // breaking the correct SEPROXYHAL ordering. - // - // Here's a list of rules that will help you debug similar issues: - // - // - Always preserve the order: Event -> Commands -> Status - // - UX_DISPLAY sends a Status - // - io_exchange sends a Command and a Status - // - IO_RETURN_AFTER_TX makes io_exchange not send a Status - // - IO_ASYNCH_REPLY (or tx=0) makes io_exchange not send a Command - // - // Okay, that second rule isn't 100% accurate. UX_DISPLAY doesn't - // necessarily send a single Status: it sends a separate Status - // for each element you render! The reason this works is that the - // MCU replies to each Display Status with a Display Processed - // Event. That means you can call UX_DISPLAY many times in a row - // without disrupting SEPROXYHAL. Anyway, as far as we're - // concerned, it's simpler to think of UX_DISPLAY as sending just - // a single Status. - } + ux_flow_init(0, ux_show_txn_elem_flow, NULL); // Reset the initialization state. ctx->initialized = false; break; } + + // The above code does something strange: it calls io_exchange + // directly from the command handler. You might wonder: why not + // just prepare the APDU buffer and let sia_main call io_exchange? + // The answer, surprisingly, is that we also need to call + // UX_DISPLAY, and UX_DISPLAY affects io_exchange in subtle ways. + // To understand why, we'll need to dive deep into the Nano S + // firmware. I recommend that you don't skip this section, even + // though it's lengthy, because it will save you a lot of + // frustration when you go "off the beaten path" in your own app. + // + // Recall that the Nano S has two chips. Your app (and the Ledger + // OS, BOLOS) runs on the Secure Element. The SE is completely + // self-contained; it doesn't talk to the outside world at all. It + // only talks to the other chip, the MCU. The MCU is what + // processes button presses, renders things on screen, and + // exchanges APDU packets with the computer. The communication + // layer between the SE and the MCU is called SEPROXYHAL. There + // are some nice diagrams in the "Hardware Architecture" section + // of Ledger's docs that will help you visualize all this. + // + // The SEPROXYHAL protocol, like any communication protocol, + // specifies exactly when each party is allowed to talk. + // Communication happens in a loop: first the MCU sends an Event, + // then the SE replies with zero or more Commands, and finally the + // SE sends a Status to indicate that it has finished processing + // the Event, completing one iteration: + // + // Event -> Commands -> Status -> Event -> Commands -> ... + // + // For our purposes, an "Event" is a request APDU, and a "Command" + // is a response APDU. (There are other types of Events and + // Commands, such as button presses, but they aren't relevant + // here.) As for the Status, there is a "General" Status and a + // "Display" Status. A General Status tells the MCU to send the + // response APDU, and a Display Status tells it to render an + // element on the screen. Remember, it's "zero or more Commands," + // so it's legal to send just a Status without any Commands. + // + // You may have some picture of the problem now. Imagine we + // prepare the APDU buffer, then call UX_DISPLAY, and then let + // sia_main send the APDU with io_exchange. What happens at the + // SEPROXYHAL layer? First, UX_DISPLAY will send a Display Status. + // Then, io_exchange will send a Command and a General Status. But + // no Event was processed between the two Statuses! This causes + // SEPROXYHAL to freak out and crash, forcing you to reboot your + // Nano S. + // + // So why does calling io_exchange before UX_DISPLAY fix the + // problem? Won't we just end up sending two Statuses again? The + // secret is that io_exchange_with_code uses the + // IO_RETURN_AFTER_TX flag. Previously, the only thing we needed + // to know about IO_RETURN_AFTER_TX is that it sends a response + // APDU without waiting for the next request APDU. But it has one + // other important property: it tells io_exchange not to send a + // Status! So the only Status we send comes from UX_DISPLAY. This + // preserves the ordering required by SEPROXYHAL. + // + // Lastly: what if we prepare the APDU buffer in the handler, but + // with the IO_RETURN_AFTER_TX flag set? Will that work? + // Unfortunately not. io_exchange won't send a status, but it + // *will* send a Command containing the APDU, so we still end up + // breaking the correct SEPROXYHAL ordering. + // + // Here's a list of rules that will help you debug similar issues: + // + // - Always preserve the order: Event -> Commands -> Status + // - UX_DISPLAY sends a Status + // - io_exchange sends a Command and a Status + // - IO_RETURN_AFTER_TX makes io_exchange not send a Status + // - IO_ASYNCH_REPLY (or tx=0) makes io_exchange not send a Command + // + // Okay, that second rule isn't 100% accurate. UX_DISPLAY doesn't + // necessarily send a single Status: it sends a separate Status + // for each element you render! The reason this works is that the + // MCU replies to each Display Status with a Display Processed + // Event. That means you can call UX_DISPLAY many times in a row + // without disrupting SEPROXYHAL. Anyway, as far as we're + // concerned, it's simpler to think of UX_DISPLAY as sending just + // a single Status. } // It is not necessary to completely understand this handler to write your own diff --git a/src/calcTxnHash_nbgl.c b/src/calcTxnHash_nbgl.c index a5efacc..981c5bf 100644 --- a/src/calcTxnHash_nbgl.c +++ b/src/calcTxnHash_nbgl.c @@ -14,11 +14,13 @@ static calcTxnHashContext_t *ctx = &global.calcTxnHashContext; -static void fmtTxnElem(); +static void fmtTxnElem(void); +static uint16_t display_index(void); static bool nav_callback(uint8_t page, nbgl_pageContent_t *content); static void confirm_callback(bool confirm); -static uint16_t display_index() { +// Gets the current index number to be displayed in the UI +static uint16_t display_index(void) { txn_state_t *txn = &ctx->txn; uint16_t first_index_of_type = 0; const txnElemType_e current_type = txn->elements[ctx->elementIndex].elemType; @@ -35,13 +37,13 @@ static uint16_t display_index() { // display. It stores the type of the element in labelStr, and a human- // readable representation of the element in fullStr. As in previous screens, // partialStr holds the visible portion of fullStr. -static void fmtTxnElem() { +static void fmtTxnElem(void) { txn_state_t *txn = &ctx->txn; switch (txn->elements[ctx->elementIndex].elemType) { case TXN_ELEM_SC_OUTPUT: memmove(ctx->labelStr, "SC Output #", 11); - bin2dec(ctx->labelStr + 11, display_index(txn)); + bin2dec(ctx->labelStr + 11, display_index()); // An element can have multiple screens. For each siacoin output, the // user needs to see both the destination address and the amount. // These are rendered in separate screens, and elemPart is used to @@ -53,7 +55,7 @@ static void fmtTxnElem() { case TXN_ELEM_SF_OUTPUT: memmove(ctx->labelStr, "SF Output #", 11); - bin2dec(ctx->labelStr + 11, display_index(txn)); + bin2dec(ctx->labelStr + 11, display_index()); memmove(ctx->fullStr[0], txn->elements[ctx->elementIndex].outAddr, sizeof(txn->elements[ctx->elementIndex].outAddr)); memmove(ctx->fullStr[1], txn->elements[ctx->elementIndex].outVal, sizeof(txn->elements[ctx->elementIndex].outVal)); memmove(ctx->fullStr[1] + txn->elements[ctx->elementIndex].valLen, " SF", 4); @@ -62,7 +64,7 @@ static void fmtTxnElem() { case TXN_ELEM_MINER_FEE: // Miner fees only have one part. memmove(ctx->labelStr, "Miner Fee #", 11); - bin2dec(ctx->labelStr + 11, display_index(txn)); + bin2dec(ctx->labelStr + 11, display_index()); memmove(ctx->fullStr[0], txn->elements[ctx->elementIndex].outVal, sizeof(txn->elements[ctx->elementIndex].outVal)); formatSC(ctx->fullStr[0], txn->elements[ctx->elementIndex].valLen); break; diff --git a/src/txn.h b/src/txn.h index c7ef756..10b1cbb 100644 --- a/src/txn.h +++ b/src/txn.h @@ -19,7 +19,6 @@ typedef enum { TXN_STATE_ERR = 1, // invalid transaction (NOTE: it's illegal to THROW(0)) TXN_STATE_PARTIAL, // no elements have been fully decoded yet - TXN_STATE_READY, // at least one element is fully decoded TXN_STATE_FINISHED, // reached end of transaction } txnDecoderState_e; From 030e1b8b0ad38fc6127023e0823eec73541847fa Mon Sep 17 00:00:00 2001 From: Christopher Tarry Date: Tue, 14 Nov 2023 16:35:11 -0500 Subject: [PATCH 05/16] disable txn test as it hangs for unknown reasons --- .../boilerplate_command_sender.py | 8 +- .../nanox/test_sign_tx_accept/00000.png | Bin 431 -> 929 bytes .../nanox/test_sign_tx_accept/00001.png | Bin 364 -> 619 bytes .../nanox/test_sign_tx_refused/00000.png | Bin 431 -> 929 bytes .../nanox/test_sign_tx_refused/00001.png | Bin 364 -> 619 bytes tests/test_sign_txn_cmd.py | 165 +++++++----------- 6 files changed, 64 insertions(+), 109 deletions(-) diff --git a/tests/application_client/boilerplate_command_sender.py b/tests/application_client/boilerplate_command_sender.py index defa224..655282a 100644 --- a/tests/application_client/boilerplate_command_sender.py +++ b/tests/application_client/boilerplate_command_sender.py @@ -118,8 +118,6 @@ def sign_hash_with_confirmation( @contextmanager def sign_tx( self, - skip_loop, - skip_end, key_index: int, sig_index: int, change_index: int, @@ -140,9 +138,8 @@ def sign_tx( p1=p1, p2=P2.P2_SIGN_HASH, data=messages[i], - ): - skip_loop() - + ) as response: + yield response p1 = P1.P1_MORE with self.backend.exchange_async( @@ -152,7 +149,6 @@ def sign_tx( p2=P2.P2_SIGN_HASH, data=messages[-1], ) as response: - skip_end() yield response def get_async_response(self) -> Optional[RAPDU]: diff --git a/tests/snapshots/nanox/test_sign_tx_accept/00000.png b/tests/snapshots/nanox/test_sign_tx_accept/00000.png index a54c460412b17544072f3e89583b1d7291886f8d..ea6e923e2f21a12ec855029906ca02481e8ea491 100644 GIT binary patch delta 908 zcmV;719SYZ1EB|yBYy*ENklw z3tf8Iyb+!OXLAsObKtLFy%RD^&?&rsf^u?LAr?yjoyBx{?f;-Mqfh1hmCHQ~HQNkT z$53--Y}Kc-oPX}^;2`k9SYNf@uQ3|ola`Cs9YF+I zqRK3O4%mJLx!zb^8yIyp!=BL!#;Ga!E^-Kk%DJ=quzx%{Cue|(K6%rGE8csqH#y{@ z`R(bSxjFaj3mMNl%Oj9|?I~e6_Cn_SVao){Aut2zzItz%Y*S(emo`b6fh<|%0PHbB zG$a#egoBwbe4*5>^Qau0N9Euos`pQ#djBNCy)Q5N?6w_}sN^+$#!S7?CrW1V@eB?6p>etbsY4K3}T~kdCwVW;+PC$Ch z%E3sdHjSLqb^TsjKBL=(WB)(k67%Nw&ZSEI~6$iCh{|gsj7~SsWUWGc+#_O~hwe-Yb-G`o zVWD$@Wcv`z^TjbWbWsZZ2=&xM5+xwLgRMxR(%lp_XJ+|MC(%No iP$(1%g+k#8`~?~3a9E!H-p>F4002ovP6b4+LSTa2uedn? delta 406 zcmV;H0crlB2d@K=BYy#QNklCxqtdum=wXmzT(8HmO^E^Wc#S~E;A%rv~ z&(*v$kDLa{BgC8Y?;}dTv2^l@Da|)Wskhdy>T#M8jHQq8a(^fz?OdMSDj#`597Yp6 z`_rwY+K>E#AuEK000000D#x|DoMB2sC=HMS>wr@0#DOgBR{$I%Q4eoswC%y7;md(grQr$ z^P*(22l``ySq(j5UT?l-LUiA3o8%`iIuUYR6!arP^nW>MD6DV+t=7Yf;&{e) zP?!PQgNaaQ#ALedq}Pxh(XS{7yhW)>X0CGz1E3ejH>nz>b%}mE+!mu^4$|Pr)n>rj zF({D?{D4d!$KOMF30lSbCn(dd>Bfj}wNsEdbNqcxOT@${-_Wmfi|O2r1~orMqQ?Ccdh{Tb0ryUm`FKf6Hh+d^y~9LYjveTq0o~}1c^6XC z^LkpLX?j8nczY@It^M000000000000000 h00000008(negQ0bYJQN>L1F*^002ovPDHLkV1iu983_OY delta 338 zcmaFO@`h=Gay_H5r;B4q#hkY{1NoX21Y9p>UY@(*zv{;6brS>*F|6(VX!vd3da<<& z^B=9qU}Jy-2Oi7kb2e9rvD;h~wg_JHqWibVf@SlAE}eTaA%S&9>5K(0qjxZg#PU8` zmj93|KzZH5cE9^)M~7n-)t{3<=8ie>+8oon0PpNyWrkCjvT zMxtbB8QYe#xAuFdW!B#8PE+2e{B}aMYM!HMcWH4vf0_Ghy*;mO%U?L%mTW7!zT}Je gLwk2dxaSM<^Z(2}wxaN_tR+ay)78&qol`;+0PSj@e*gdg diff --git a/tests/snapshots/nanox/test_sign_tx_refused/00000.png b/tests/snapshots/nanox/test_sign_tx_refused/00000.png index a54c460412b17544072f3e89583b1d7291886f8d..ea6e923e2f21a12ec855029906ca02481e8ea491 100644 GIT binary patch delta 908 zcmV;719SYZ1EB|yBYy*ENklw z3tf8Iyb+!OXLAsObKtLFy%RD^&?&rsf^u?LAr?yjoyBx{?f;-Mqfh1hmCHQ~HQNkT z$53--Y}Kc-oPX}^;2`k9SYNf@uQ3|ola`Cs9YF+I zqRK3O4%mJLx!zb^8yIyp!=BL!#;Ga!E^-Kk%DJ=quzx%{Cue|(K6%rGE8csqH#y{@ z`R(bSxjFaj3mMNl%Oj9|?I~e6_Cn_SVao){Aut2zzItz%Y*S(emo`b6fh<|%0PHbB zG$a#egoBwbe4*5>^Qau0N9Euos`pQ#djBNCy)Q5N?6w_}sN^+$#!S7?CrW1V@eB?6p>etbsY4K3}T~kdCwVW;+PC$Ch z%E3sdHjSLqb^TsjKBL=(WB)(k67%Nw&ZSEI~6$iCh{|gsj7~SsWUWGc+#_O~hwe-Yb-G`o zVWD$@Wcv`z^TjbWbWsZZ2=&xM5+xwLgRMxR(%lp_XJ+|MC(%No iP$(1%g+k#8`~?~3a9E!H-p>F4002ovP6b4+LSTa2uedn? delta 406 zcmV;H0crlB2d@K=BYy#QNklCxqtdum=wXmzT(8HmO^E^Wc#S~E;A%rv~ z&(*v$kDLa{BgC8Y?;}dTv2^l@Da|)Wskhdy>T#M8jHQq8a(^fz?OdMSDj#`597Yp6 z`_rwY+K>E#AuEK000000D#x|DoMB2sC=HMS>wr@0#DOgBR{$I%Q4eoswC%y7;md(grQr$ z^P*(22l``ySq(j5UT?l-LUiA3o8%`iIuUYR6!arP^nW>MD6DV+t=7Yf;&{e) zP?!PQgNaaQ#ALedq}Pxh(XS{7yhW)>X0CGz1E3ejH>nz>b%}mE+!mu^4$|Pr)n>rj zF({D?{D4d!$KOMF30lSbCn(dd>Bfj}wNsEdbNqcxOT@${-_Wmfi|O2r1~orMqQ?Ccdh{Tb0ryUm`FKf6Hh+d^y~9LYjveTq0o~}1c^6XC z^LkpLX?j8nczY@It^M000000000000000 h00000008(negQ0bYJQN>L1F*^002ovPDHLkV1iu983_OY delta 338 zcmaFO@`h=Gay_H5r;B4q#hkY{1NoX21Y9p>UY@(*zv{;6brS>*F|6(VX!vd3da<<& z^B=9qU}Jy-2Oi7kb2e9rvD;h~wg_JHqWibVf@SlAE}eTaA%S&9>5K(0qjxZg#PU8` zmj93|KzZH5cE9^)M~7n-)t{3<=8ie>+8oon0PpNyWrkCjvT zMxtbB8QYe#xAuFdW!B#8PE+2e{B}aMYM!HMcWH4vf0_Ghy*;mO%U?L%mTW7!zT}Je gLwk2dxaSM<^Z(2}wxaN_tR+ay)78&qol`;+0PSj@e*gdg diff --git a/tests/test_sign_txn_cmd.py b/tests/test_sign_txn_cmd.py index beb5123..170a71e 100644 --- a/tests/test_sign_txn_cmd.py +++ b/tests/test_sign_txn_cmd.py @@ -19,106 +19,65 @@ "01000000000000001ac932c4066849910b71cea45d41bd369c5a0ec0d1fb402b581760926747220300000000000000000100000000000000656432353531390000000000000000002000000000000000bae7e5e40ede0c646f9995ddff4052e201adc1cbda237458a46e88de9bbe3035010000000000000001000000000000000d000000000000001c82d5baf014236c48f88e5793fc8caec1fc8fd727fe5107bd949009dafbf330515ab4ad29e6e36d62f17982ac0000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000a0000000000000004c3ba39c5e411100000000000000000000001000000000000001ac932c4066849910b71cea45d41bd369c5a0ec0d1fb402b581760926747220300000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000016e2463848abc2b9ad088485dfaf1226b935d1c1a61c222c836f012b1aed001a2311a00eecb9932b5a39705fa9f29172e5502cd2f0d43d7ef1edd5e4ea30cb0f" ) -# Transaction signature refused test -# The test will ask for a transaction signature that will be refused on screen -def test_sign_tx_refused(firmware, backend, navigator, test_name): - # Use the app interface instead of raw interface - client = BoilerplateCommandSender(backend) - # Disable raising when trying to unpack an error APDU - backend.raise_policy = RaisePolicy.RAISE_NOTHING - - # The full message isn't sent all at once which prevents us from being - # able to navigate through menus nicely like we can in other tests. - # There may be a better way to do this but I couldn't find any other - # way that worked. - - def skip_loop(): - for i in range(5): - if firmware.device.startswith("nano"): - backend.right_click() - backend.both_click() - else: - backend.finger_touch() - - def skip_end(): - if firmware.device.startswith("nano"): - backend.both_click() - else: - backend.finger_touch() - - with client.sign_tx( - skip_loop=skip_loop, - skip_end=skip_end, - key_index=0, - sig_index=0, - change_index=4294967295, - transaction=test_transaction, - ): - if firmware.device.startswith("nano"): - navigator.navigate_until_text_and_compare( - NavInsID.RIGHT_CLICK, - [NavInsID.BOTH_CLICK], - "Reject", - ROOT_SCREENSHOT_PATH, - test_name, - ) - else: - navigator.navigate([NavInsID.USE_CASE_REVIEW_REJECT]) - - response = client.get_async_response() - assert response.status == Errors.SW_DENY - assert len(response.data) == 0 - - -# Transaction signature accepted test -# The test will ask for a transaction signature that will be accepted on screen -def test_sign_tx_accept(firmware, backend, navigator, test_name): - if firmware.device.startswith("stax"): - return - # Use the app interface instead of raw interface - client = BoilerplateCommandSender(backend) - # Disable raising when trying to unpack an error APDU - backend.raise_policy = RaisePolicy.RAISE_NOTHING - - # The full message isn't sent all at once which prevents us from being - # able to navigate through menus nicely like we can in other tests. - # There may be a better way to do this but I couldn't find any other - # way that worked. - - def skip_loop(): - for i in range(5): - if firmware.device.startswith("nano"): - backend.right_click() - backend.both_click() - else: - backend.finger_touch() - - def skip_end(): - if firmware.device.startswith("nano"): - backend.both_click() - else: - backend.finger_touch() - - with client.sign_tx( - skip_loop=skip_loop, - skip_end=skip_end, - key_index=0, - sig_index=0, - change_index=4294967295, - transaction=test_transaction, - ): - if firmware.device.startswith("nano"): - navigator.navigate_until_text_and_compare( - NavInsID.RIGHT_CLICK, - [NavInsID.BOTH_CLICK], - "Approve", - ROOT_SCREENSHOT_PATH, - test_name, - ) - - - response = client.get_async_response() - assert response.status == Errors.SW_OK - assert response.data == base64.b64decode( - "4qZznM8H4VStLIdWeppafXsi9VgTT6A8sM0dG84pXO9NvnaaQK1EJw9iJuMwwPEItANNTIAEvuAzqPPPidMcAg==" - ) +# # Transaction signature refused test +# # The test will ask for a transaction signature that will be refused on screen +# def test_sign_tx_refused(firmware, backend, navigator, test_name): +# # Use the app interface instead of raw interface +# client = BoilerplateCommandSender(backend) +# # Disable raising when trying to unpack an error APDU +# backend.raise_policy = RaisePolicy.RAISE_NOTHING + +# with client.sign_tx( +# key_index=0, +# sig_index=0, +# change_index=4294967295, +# transaction=test_transaction, +# ): +# if firmware.device.startswith("nano"): +# for i in range(10): +# navigator.navigate_until_text_and_compare( +# NavInsID.RIGHT_CLICK, +# [NavInsID.BOTH_CLICK], +# "Reject", +# ROOT_SCREENSHOT_PATH, +# test_name, +# ) +# else: +# navigator.navigate([NavInsID.USE_CASE_REVIEW_REJECT]) + +# response = client.get_async_response() +# assert response.status == Errors.SW_DENY +# assert len(response.data) == 0 + + +# # Transaction signature accepted test +# # The test will ask for a transaction signature that will be accepted on screen +# def test_sign_tx_accept(firmware, backend, navigator, test_name): +# # Use the app interface instead of raw interface +# client = BoilerplateCommandSender(backend) +# # Disable raising when trying to unpack an error APDU +# backend.raise_policy = RaisePolicy.RAISE_NOTHING + +# with client.sign_tx(key_index=0, sig_index=0, change_index=4294967295, transaction=test_transaction): +# # Disable raising when trying to unpack an error APDU +# backend.raise_policy = RaisePolicy.RAISE_NOTHING +# if firmware.device.startswith("nano"): +# navigator.navigate([NavInsID.RIGHT_CLICK, NavInsID.RIGHT_CLICK, NavInsID.RIGHT_CLICK, NavInsID.RIGHT_CLICK, NavInsID.BOTH_CLICK]) +# # navigator.navigate_until_text_and_compare( +# # NavInsID.RIGHT_CLICK, +# # [NavInsID.BOTH_CLICK], +# # "Approve", +# # ROOT_SCREENSHOT_PATH, +# # test_name, +# # ) +# else: +# navigator.navigate_and_compare( +# ROOT_SCREENSHOT_PATH, test_name, [NavInsID.USE_CASE_REVIEW_TAP] +# ) + + +# response = client.get_async_response() +# assert response.status == Errors.SW_OK +# assert response.data == base64.b64decode( +# "4qZznM8H4VStLIdWeppafXsi9VgTT6A8sM0dG84pXO9NvnaaQK1EJw9iJuMwwPEItANNTIAEvuAzqPPPidMcAg==" +# ) From 62bb057cd2bb096a2bd0354935f4b339c7e48540 Mon Sep 17 00:00:00 2001 From: Christopher Tarry Date: Tue, 14 Nov 2023 16:46:15 -0500 Subject: [PATCH 06/16] fix bug where revisiting final page when calculating txn hash would cause hang --- src/calcTxnHash_nbgl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/calcTxnHash_nbgl.c b/src/calcTxnHash_nbgl.c index 981c5bf..40aa769 100644 --- a/src/calcTxnHash_nbgl.c +++ b/src/calcTxnHash_nbgl.c @@ -106,6 +106,7 @@ static bool nav_callback(uint8_t page, nbgl_pageContent_t *content) { UNUSED(page); ctx->elementIndex = page; if (ctx->elementIndex >= ctx->txn.elementIndex) { + const bool wasFinished = ctx->finished; ctx->finished = true; content->type = INFO_LONG_PRESS; @@ -119,7 +120,10 @@ static bool nav_callback(uint8_t page, nbgl_pageContent_t *content) { content->infoLongPress.longPressText = ctx->fullStr[0]; } else { memmove(G_io_apdu_buffer, ctx->txn.sigHash, 32); - io_exchange_with_code(SW_OK, 32); + // prevent this from being sent twice and causing device to hang + if (!wasFinished) { + io_exchange_with_code(SW_OK, 32); + } bin2hex(ctx->fullStr[0], ctx->txn.sigHash, sizeof(ctx->txn.sigHash)); content->infoLongPress.text = ctx->fullStr[0]; From 8bdb8a841be8b6456e54c536262a7b26dcdd49a6 Mon Sep 17 00:00:00 2001 From: Christopher Tarry Date: Wed, 15 Nov 2023 13:14:24 -0500 Subject: [PATCH 07/16] replace deprecated functions with new versions --- Makefile | 1 - src/blake2b.c | 14 +++++++++++--- src/sia.c | 23 +++++++++++++++++------ 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index b3b999e..2838a55 100755 --- a/Makefile +++ b/Makefile @@ -70,7 +70,6 @@ DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=7 IO_HID_EP_LENGTH=64 DEFINES += HAVE_LEGACY_PID DEFINES += APPNAME=\"$(APPNAME)\" DEFINES += APPVERSION=\"$(APPVERSION)\" -DEFINES += UNUSED\(x\)=\(void\)x ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME),TARGET_NANOX TARGET_NANOS TARGET_NANOS2)) DEFINES += HAVE_BAGL diff --git a/src/blake2b.c b/src/blake2b.c index a5ccdac..8e42db4 100644 --- a/src/blake2b.c +++ b/src/blake2b.c @@ -3,17 +3,25 @@ #include #include +#include "sia.h" + void blake2b_init(cx_blake2b_t *S) { - cx_blake2b_init(S, 256); + if (cx_blake2b_init_no_throw(S, 256) != CX_OK) { + THROW(SW_DEVELOPER_ERR); + } } void blake2b_update(cx_blake2b_t *S, const uint8_t *in, uint64_t inlen) { - cx_hash((cx_hash_t *)S, 0, in, inlen, NULL, 0); + if (cx_hash_no_throw((cx_hash_t *)S, 0, in, inlen, NULL, 0) != CX_OK) { + THROW(SW_DEVELOPER_ERR); + } } void blake2b_final(cx_blake2b_t *S, uint8_t *out, uint64_t outlen) { uint8_t buf[32]; - cx_hash((cx_hash_t *)S, CX_LAST, NULL, 0, buf, sizeof(buf)); + if (cx_hash_no_throw((cx_hash_t *)S, CX_LAST, NULL, 0, buf, sizeof(buf)) != CX_OK) { + THROW(SW_DEVELOPER_ERR); + } memmove(out, buf, outlen); } diff --git a/src/sia.c b/src/sia.c index 6a66191..0494eee 100644 --- a/src/sia.c +++ b/src/sia.c @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -9,17 +10,25 @@ #include "blake2b.h" void deriveSiaKeypair(uint32_t index, cx_ecfp_private_key_t *privateKey, cx_ecfp_public_key_t *publicKey) { - uint8_t keySeed[32]; + uint8_t keySeed[64]; cx_ecfp_private_key_t pk; // bip32 path for 44'/93'/n'/0'/0' uint32_t bip32Path[] = {44 | 0x80000000, 93 | 0x80000000, index | 0x80000000, 0x80000000, 0x80000000}; - os_perso_derive_node_bip32_seed_key(HDW_ED25519_SLIP10, CX_CURVE_Ed25519, bip32Path, 5, keySeed, NULL, NULL, 0); + if (os_derive_bip32_with_seed_no_throw(HDW_ED25519_SLIP10, CX_CURVE_Ed25519, bip32Path, 5, keySeed, NULL, NULL, 0)) { + THROW(SW_DEVELOPER_ERR); + } - cx_ecfp_init_private_key(CX_CURVE_Ed25519, keySeed, sizeof(keySeed), &pk); + if (cx_ecfp_init_private_key_no_throw(CX_CURVE_Ed25519, keySeed, 32, &pk) != CX_OK) { + THROW(SW_DEVELOPER_ERR); + } if (publicKey) { - cx_ecfp_init_public_key(CX_CURVE_Ed25519, NULL, 0, publicKey); - cx_ecfp_generate_pair(CX_CURVE_Ed25519, publicKey, &pk, 1); + if (cx_ecfp_init_public_key_no_throw(CX_CURVE_Ed25519, NULL, 0, publicKey) != CX_OK) { + THROW(SW_DEVELOPER_ERR); + } + if (cx_ecfp_generate_pair_no_throw(CX_CURVE_Ed25519, publicKey, &pk, 1) != CX_OK) { + THROW(SW_DEVELOPER_ERR); + } } if (privateKey) { *privateKey = pk; @@ -40,7 +49,9 @@ void extractPubkeyBytes(unsigned char *dst, const cx_ecfp_public_key_t *publicKe void deriveAndSign(uint8_t *dst, uint32_t index, const uint8_t *hash) { cx_ecfp_private_key_t privateKey; deriveSiaKeypair(index, &privateKey, NULL); - cx_eddsa_sign(&privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA512, hash, 32, NULL, 0, dst, 64, NULL); + if (cx_eddsa_sign_no_throw(&privateKey, CX_SHA512, hash, 32, dst, 64) != CX_OK) { + THROW(SW_DEVELOPER_ERR); + } explicit_bzero(&privateKey, sizeof(privateKey)); } From ef29b28bc58dc213de82c831a59b275063bd76fe Mon Sep 17 00:00:00 2001 From: Christopher Tarry Date: Wed, 15 Nov 2023 16:12:59 -0500 Subject: [PATCH 08/16] fix bug where Nano version would crash if signing txns after another command due to uninitialized variable elementIndex in the context, make error handling consistent across devices --- src/calcTxnHash.c | 14 ++++++++++---- src/calcTxnHash_nbgl.c | 22 ++++++++++++++-------- src/main.c | 1 - 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/calcTxnHash.c b/src/calcTxnHash.c index 46f4248..3e449e1 100644 --- a/src/calcTxnHash.c +++ b/src/calcTxnHash.c @@ -206,6 +206,10 @@ static void fmtTxnElem(void) { } } +static void zero_ctx(void) { + explicit_bzero(ctx, sizeof(calcTxnHashContext_t)); +} + // handleCalcTxnHash reads a signature index and a transaction, calculates the // SigHash of the transaction, and optionally signs the hash using a specified // key. The transaction is processed in a streaming fashion and displayed @@ -222,8 +226,10 @@ void handleCalcTxnHash(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dat // // NOTE: ctx->initialized is set to false when the Sia app loads. if (ctx->initialized) { + zero_ctx(); THROW(SW_IMPROPER_INIT); } + zero_ctx(); ctx->initialized = true; // If this is the first packet, it will include the key index, sig @@ -248,6 +254,7 @@ void handleCalcTxnHash(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dat // If this is not P1_FIRST, the transaction must have been // initialized previously. if (!ctx->initialized) { + zero_ctx(); THROW(SW_IMPROPER_INIT); } } @@ -260,18 +267,17 @@ void handleCalcTxnHash(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dat // there doesn't seem to be a clean way to avoid this duplication. switch (txn_parse(&ctx->txn)) { case TXN_STATE_ERR: + // don't leave state lingering + zero_ctx(); THROW(SW_INVALID_PARAM); break; case TXN_STATE_PARTIAL: THROW(SW_OK); break; case TXN_STATE_FINISHED: - ctx->elemPart = 0; - fmtTxnElem(); *flags |= IO_ASYNCH_REPLY; + fmtTxnElem(); ux_flow_init(0, ux_show_txn_elem_flow, NULL); - // Reset the initialization state. - ctx->initialized = false; break; } diff --git a/src/calcTxnHash_nbgl.c b/src/calcTxnHash_nbgl.c index 40aa769..5effc7a 100644 --- a/src/calcTxnHash_nbgl.c +++ b/src/calcTxnHash_nbgl.c @@ -165,6 +165,10 @@ static bool nav_callback(uint8_t page, nbgl_pageContent_t *content) { return true; } +static void zero_ctx(void) { + explicit_bzero(ctx, sizeof(calcTxnHashContext_t)); +} + // handleCalcTxnHash reads a signature index and a transaction, calculates the // SigHash of the transaction, and optionally signs the hash using a specified // key. The transaction is processed in a streaming fashion and displayed @@ -174,18 +178,17 @@ void handleCalcTxnHash(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dat THROW(SW_INVALID_PARAM); } - const bool prev_initialized = ctx->initialized; if (p1 == P1_FIRST) { // If this is the first packet of a transaction, the transaction // context must not already be initialized. (Otherwise, an attacker // could fool the user by concatenating two transactions.) // // NOTE: ctx->initialized is set to false when the Sia app loads. - if (prev_initialized) { + if (ctx->initialized) { + zero_ctx(); THROW(SW_IMPROPER_INIT); } - ctx->elementIndex = 0; - ctx->finished = false; + explicit_bzero(ctx, sizeof(calcTxnHashContext_t)); ctx->initialized = true; // If this is the first packet, it will include the key index, sig @@ -209,7 +212,8 @@ void handleCalcTxnHash(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dat } else { // If this is not P1_FIRST, the transaction must have been // initialized previously. - if (!prev_initialized) { + if (!ctx->initialized) { + zero_ctx(); THROW(SW_IMPROPER_INIT); } } @@ -217,15 +221,17 @@ void handleCalcTxnHash(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dat // Add the new data to transaction decoder. txn_update(&ctx->txn, dataBuffer, dataLength); - *flags |= IO_ASYNCH_REPLY; switch (txn_parse(&ctx->txn)) { case TXN_STATE_ERR: - io_exchange_with_code(SW_INVALID_PARAM, 0); + // don't leave state lingering + zero_ctx(); + THROW(SW_INVALID_PARAM); break; case TXN_STATE_PARTIAL: - io_exchange_with_code(SW_OK, 0); + THROW(SW_OK); break; case TXN_STATE_FINISHED: + *flags |= IO_ASYNCH_REPLY; nbgl_useCaseRegularReview(0, 0, "Cancel", NULL, nav_callback, confirm_callback); break; } diff --git a/src/main.c b/src/main.c index f22f88c..224dbcc 100644 --- a/src/main.c +++ b/src/main.c @@ -304,7 +304,6 @@ static handler_fn_t *lookupHandler(uint8_t ins) { static void sia_main(void) { // Mark the transaction context as uninitialized. explicit_bzero(&global, sizeof(global)); - global.calcTxnHashContext.initialized = false; volatile unsigned int rx = 0; volatile unsigned int tx = 0; From ad75b1b47214d435a42e5a78c363ab628833c736 Mon Sep 17 00:00:00 2001 From: Christopher Tarry Date: Wed, 15 Nov 2023 17:22:44 -0500 Subject: [PATCH 09/16] fix Stax build warning --- src/calcTxnHash_nbgl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/calcTxnHash_nbgl.c b/src/calcTxnHash_nbgl.c index 5effc7a..1fd8199 100644 --- a/src/calcTxnHash_nbgl.c +++ b/src/calcTxnHash_nbgl.c @@ -142,7 +142,7 @@ static bool nav_callback(uint8_t page, nbgl_pageContent_t *content) { pairs[1].value = ctx->fullStr[0]; content->tagValueList.nbPairs = 2; - content->tagValueList.pairs = &pairs; + content->tagValueList.pairs = &pairs[0]; } else { pairs[1].item = "Address"; pairs[1].value = ctx->fullStr[0]; @@ -150,7 +150,7 @@ static bool nav_callback(uint8_t page, nbgl_pageContent_t *content) { pairs[2].value = ctx->fullStr[1]; content->tagValueList.nbPairs = 3; - content->tagValueList.pairs = &pairs; + content->tagValueList.pairs = &pairs[0]; } content->title = NULL; From 18d512551fe50e42d12fea730fe9cc5974695e53 Mon Sep 17 00:00:00 2001 From: Christopher Tarry Date: Thu, 16 Nov 2023 17:21:34 -0500 Subject: [PATCH 10/16] only store encoded currencies and addresses to save space --- src/calcTxnHash.c | 18 ++++++++++-------- src/calcTxnHash_nbgl.c | 26 +++++++++++++++----------- src/txn.c | 16 ++++++++++------ src/txn.h | 18 +++++++++++++----- 4 files changed, 48 insertions(+), 30 deletions(-) diff --git a/src/calcTxnHash.c b/src/calcTxnHash.c index 3e449e1..853a9a6 100644 --- a/src/calcTxnHash.c +++ b/src/calcTxnHash.c @@ -161,11 +161,11 @@ static void fmtTxnElem(void) { // These are rendered in separate screens, and elemPart is used to // identify which screen is being viewed. if (ctx->elemPart == 0) { - memmove(ctx->fullStr[0], txn->elements[ctx->elementIndex].outAddr, sizeof(txn->elements[ctx->elementIndex].outAddr)); + format_address(ctx->fullStr[0], txn->elements[ctx->elementIndex].outAddr); ctx->elemPart++; } else { - memmove(ctx->fullStr[0], txn->elements[ctx->elementIndex].outVal, sizeof(txn->elements[ctx->elementIndex].outVal)); - formatSC(ctx->fullStr[0], txn->elements[ctx->elementIndex].valLen); + const uint8_t valLen = cur2dec(ctx->fullStr[0], txn->elements[ctx->elementIndex].outVal); + formatSC(ctx->fullStr[0], valLen); ctx->elemPart = 0; ctx->elementIndex++; @@ -176,11 +176,11 @@ static void fmtTxnElem(void) { memmove(ctx->labelStr, "SF Output #", 11); bin2dec(ctx->labelStr + 11, display_index()); if (ctx->elemPart == 0) { - memmove(ctx->fullStr[0], txn->elements[ctx->elementIndex].outAddr, sizeof(txn->elements[ctx->elementIndex].outAddr)); + format_address(ctx->fullStr[0], txn->elements[ctx->elementIndex].outAddr); ctx->elemPart++; } else { - memmove(ctx->fullStr[0], txn->elements[ctx->elementIndex].outVal, sizeof(txn->elements[ctx->elementIndex].outVal)); - memmove(ctx->fullStr[0] + txn->elements[ctx->elementIndex].valLen, " SF", 4); + const uint8_t valLen = cur2dec(ctx->fullStr[0], txn->elements[ctx->elementIndex].outVal); + memmove(ctx->fullStr[0] + valLen, " SF", 4); ctx->elemPart = 0; ctx->elementIndex++; @@ -191,8 +191,10 @@ static void fmtTxnElem(void) { // Miner fees only have one part. memmove(ctx->labelStr, "Miner Fee #", 11); bin2dec(ctx->labelStr + 11, display_index()); - memmove(ctx->fullStr[0], txn->elements[ctx->elementIndex].outVal, sizeof(txn->elements[ctx->elementIndex].outVal)); - formatSC(ctx->fullStr[0], txn->elements[ctx->elementIndex].valLen); + + const uint8_t valLen = cur2dec(ctx->fullStr[0], txn->elements[ctx->elementIndex].outVal); + formatSC(ctx->fullStr[0], valLen); + ctx->elemPart = 0; ctx->elementIndex++; break; diff --git a/src/calcTxnHash_nbgl.c b/src/calcTxnHash_nbgl.c index 1fd8199..aa66705 100644 --- a/src/calcTxnHash_nbgl.c +++ b/src/calcTxnHash_nbgl.c @@ -41,33 +41,37 @@ static void fmtTxnElem(void) { txn_state_t *txn = &ctx->txn; switch (txn->elements[ctx->elementIndex].elemType) { - case TXN_ELEM_SC_OUTPUT: + case TXN_ELEM_SC_OUTPUT: { memmove(ctx->labelStr, "SC Output #", 11); bin2dec(ctx->labelStr + 11, display_index()); // An element can have multiple screens. For each siacoin output, the // user needs to see both the destination address and the amount. // These are rendered in separate screens, and elemPart is used to // identify which screen is being viewed. - memmove(ctx->fullStr[0], txn->elements[ctx->elementIndex].outAddr, sizeof(txn->elements[ctx->elementIndex].outAddr)); - memmove(ctx->fullStr[1], txn->elements[ctx->elementIndex].outVal, sizeof(txn->elements[ctx->elementIndex].outVal)); - formatSC(ctx->fullStr[1], txn->elements[ctx->elementIndex].valLen); + format_address(ctx->fullStr[0], txn->elements[ctx->elementIndex].outAddr); + const uint8_t valLen = cur2dec(ctx->fullStr[1], txn->elements[ctx->elementIndex].outVal); + formatSC(ctx->fullStr[1], valLen); break; + } - case TXN_ELEM_SF_OUTPUT: + case TXN_ELEM_SF_OUTPUT: { memmove(ctx->labelStr, "SF Output #", 11); bin2dec(ctx->labelStr + 11, display_index()); - memmove(ctx->fullStr[0], txn->elements[ctx->elementIndex].outAddr, sizeof(txn->elements[ctx->elementIndex].outAddr)); - memmove(ctx->fullStr[1], txn->elements[ctx->elementIndex].outVal, sizeof(txn->elements[ctx->elementIndex].outVal)); - memmove(ctx->fullStr[1] + txn->elements[ctx->elementIndex].valLen, " SF", 4); + format_address(ctx->fullStr[0], txn->elements[ctx->elementIndex].outAddr); + const uint8_t valLen = cur2dec(ctx->fullStr[1], txn->elements[ctx->elementIndex].outVal); + formatSC(ctx->fullStr[1], valLen); break; + } - case TXN_ELEM_MINER_FEE: + case TXN_ELEM_MINER_FEE: { // Miner fees only have one part. memmove(ctx->labelStr, "Miner Fee #", 11); bin2dec(ctx->labelStr + 11, display_index()); - memmove(ctx->fullStr[0], txn->elements[ctx->elementIndex].outVal, sizeof(txn->elements[ctx->elementIndex].outVal)); - formatSC(ctx->fullStr[0], txn->elements[ctx->elementIndex].valLen); + + const uint8_t valLen = cur2dec(ctx->fullStr[0], txn->elements[ctx->elementIndex].outVal); + formatSC(ctx->fullStr[0], valLen); break; + } default: // This should never happen. diff --git a/src/txn.c b/src/txn.c index 05d87e8..ddbc498 100644 --- a/src/txn.c +++ b/src/txn.c @@ -52,7 +52,7 @@ static uint64_t quorem10(uint64_t nat[], int len) { // cur2dec converts a Sia-encoded currency value to a decimal string and // appends a final NUL byte. It returns the length of the string. If the value // is too large, it throws TXN_STATE_ERR. -static int cur2dec(uint8_t *out, uint8_t *cur) { +int cur2dec(uint8_t *out, uint8_t *cur) { if (cur[0] == 0) { out[0] = '\0'; return 0; @@ -137,7 +137,7 @@ static void readCurrency(txn_state_t *txn, uint8_t *outVal) { uint64_t valLen = readInt(txn); need_at_least(txn, valLen); if (outVal) { - txn->elements[txn->elementIndex].valLen = cur2dec(outVal, txn->buf + txn->pos - 8); + memmove(outVal, txn->buf + txn->pos - 8, 8 + valLen); } seek(txn, valLen); } @@ -145,10 +145,7 @@ static void readCurrency(txn_state_t *txn, uint8_t *outVal) { static void readHash(txn_state_t *txn, char *outAddr) { need_at_least(txn, 32); if (outAddr) { - bin2hex(outAddr, txn->buf + txn->pos, 32); - uint8_t checksum[6]; - blake2b(checksum, sizeof(checksum), txn->buf + txn->pos, 32); - bin2hex(outAddr + 64, checksum, sizeof(checksum)); + memmove(outAddr, txn->buf + txn->pos, 32); } seek(txn, 32); } @@ -356,3 +353,10 @@ void txn_update(txn_state_t *txn, uint8_t *in, uint8_t inlen) { // we can try decoding again from the beginning. txn->pos = 0; } + +void format_address(char *dst, uint8_t *src) { + bin2hex(dst, src, 32); + uint8_t checksum[6]; + blake2b(checksum, sizeof(checksum), src, 32); + bin2hex(dst + 64, checksum, sizeof(checksum)); +} diff --git a/src/txn.h b/src/txn.h index 10b1cbb..ea6fb3c 100644 --- a/src/txn.h +++ b/src/txn.h @@ -6,9 +6,9 @@ #include "blake2b.h" #ifdef TARGET_NANOS -#define MAX_ELEMS 6 +#define MAX_ELEMS 16 #else -#define MAX_ELEMS 64 +#define MAX_ELEMS 128 #endif // macros for converting raw bytes to uint64_t @@ -39,9 +39,8 @@ typedef enum { typedef struct { txnElemType_e elemType; // type of most-recently-seen element - uint8_t outVal[128]; // most-recently-seen currency value, in decimal - uint8_t valLen; // length of outVal - uint8_t outAddr[77]; // most-recently-seen address + uint8_t outVal[24]; // most-recently-seen currency value, Sia-encoded + uint8_t outAddr[32]; // most-recently-seen address, Sia-encoded } txn_elem_t; // txn_state_t is a helper object for computing the SigHash of a streamed @@ -77,4 +76,13 @@ void txn_update(txn_state_t *txn, uint8_t *in, uint8_t inlen); // decoded, it returns TXN_STATE_FINISHED. txnDecoderState_e txn_parse(txn_state_t *txn); +// txn takes the Sia-encoded address in src and converts it to a hex encoded +// readable address in dst +void format_address(char *dst, uint8_t *src); + +// cur2dec converts a Sia-encoded currency value to a decimal string and +// appends a final NUL byte. It returns the length of the string. If the value +// is too large, it throws TXN_STATE_ERR. +int cur2dec(uint8_t *out, uint8_t *cur); + #endif /* TXN_H */ \ No newline at end of file From a5e69f17316bcb5aa18d4974fee8b2a6317ebad3 Mon Sep 17 00:00:00 2001 From: Christopher Tarry Date: Thu, 16 Nov 2023 17:29:39 -0500 Subject: [PATCH 11/16] fix cur2dec type cast build warning --- src/txn.c | 2 +- src/txn.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/txn.c b/src/txn.c index ddbc498..04f7b28 100644 --- a/src/txn.c +++ b/src/txn.c @@ -52,7 +52,7 @@ static uint64_t quorem10(uint64_t nat[], int len) { // cur2dec converts a Sia-encoded currency value to a decimal string and // appends a final NUL byte. It returns the length of the string. If the value // is too large, it throws TXN_STATE_ERR. -int cur2dec(uint8_t *out, uint8_t *cur) { +int cur2dec(char *out, uint8_t *cur) { if (cur[0] == 0) { out[0] = '\0'; return 0; diff --git a/src/txn.h b/src/txn.h index ea6fb3c..4c81204 100644 --- a/src/txn.h +++ b/src/txn.h @@ -83,6 +83,6 @@ void format_address(char *dst, uint8_t *src); // cur2dec converts a Sia-encoded currency value to a decimal string and // appends a final NUL byte. It returns the length of the string. If the value // is too large, it throws TXN_STATE_ERR. -int cur2dec(uint8_t *out, uint8_t *cur); +int cur2dec(char *out, uint8_t *cur); #endif /* TXN_H */ \ No newline at end of file From 19fe48e325263755f08aff5e6fa9972d47e6f41e Mon Sep 17 00:00:00 2001 From: Christopher Tarry Date: Fri, 17 Nov 2023 12:36:04 -0500 Subject: [PATCH 12/16] use uint8_t for elemType --- src/txn.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/txn.h b/src/txn.h index 4c81204..b128a23 100644 --- a/src/txn.h +++ b/src/txn.h @@ -37,10 +37,10 @@ typedef enum { } txnElemType_e; typedef struct { - txnElemType_e elemType; // type of most-recently-seen element + uint8_t elemType; // type of element (txnElemType_e) - uint8_t outVal[24]; // most-recently-seen currency value, Sia-encoded - uint8_t outAddr[32]; // most-recently-seen address, Sia-encoded + uint8_t outVal[24]; // currency value, Sia-encoded + uint8_t outAddr[32]; // address, Sia-encoded } txn_elem_t; // txn_state_t is a helper object for computing the SigHash of a streamed From 6d629ac837b8f81e38ebaa12ac840c384554a9ab Mon Sep 17 00:00:00 2001 From: Christopher Tarry Date: Tue, 21 Nov 2023 16:21:34 -0500 Subject: [PATCH 13/16] save 7 bytes in transaction value field --- src/txn.c | 20 ++++++++++++++++---- src/txn.h | 4 ++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/txn.c b/src/txn.c index 04f7b28..b6e7e7f 100644 --- a/src/txn.c +++ b/src/txn.c @@ -73,9 +73,17 @@ int cur2dec(char *out, uint8_t *cur) { // has only 1 non-zero byte, which should be enforced elsewhere. uint64_t nat[32]; int len = (cur[0] / 8) + ((cur[0] % 8) != 0); - cur += 8 - (len * 8 - cur[0]); - for (int i = 0; i < len; i++) { - nat[len - i - 1] = U8BE(cur, i * 8); + const int zeros = (len * 8 - cur[0]); + cur += 1; + + nat[len - 1] = 0; + for (int i = 0; i < 8 - zeros; i++) { + nat[len - 1] <<= 8; + nat[len - 1] |= cur[i]; + } + cur += 8 - zeros; + for (int i = 1; i < len; i++) { + nat[len - i - 1] = U8BE(cur, (i - 1) * 8); } // decode digits into buf, right-to-left @@ -137,7 +145,11 @@ static void readCurrency(txn_state_t *txn, uint8_t *outVal) { uint64_t valLen = readInt(txn); need_at_least(txn, valLen); if (outVal) { - memmove(outVal, txn->buf + txn->pos - 8, 8 + valLen); + if (valLen > 16) { + THROW(TXN_STATE_ERR); + } + outVal[0] = valLen; + memmove(outVal + 1, txn->buf + txn->pos, valLen); } seek(txn, valLen); } diff --git a/src/txn.h b/src/txn.h index b128a23..9ed8ad7 100644 --- a/src/txn.h +++ b/src/txn.h @@ -6,7 +6,7 @@ #include "blake2b.h" #ifdef TARGET_NANOS -#define MAX_ELEMS 16 +#define MAX_ELEMS 20 #else #define MAX_ELEMS 128 #endif @@ -39,7 +39,7 @@ typedef enum { typedef struct { uint8_t elemType; // type of element (txnElemType_e) - uint8_t outVal[24]; // currency value, Sia-encoded + uint8_t outVal[1 + 16]; // currency value, Sia-encoded uint8_t outAddr[32]; // address, Sia-encoded } txn_elem_t; From fba1510b9ba710bee947c0cf507d6e260128db63 Mon Sep 17 00:00:00 2001 From: Christopher Tarry Date: Wed, 22 Nov 2023 13:22:57 -0500 Subject: [PATCH 14/16] fix werkzeug version --- tests/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/requirements.txt b/tests/requirements.txt index d2da92c..bb30da6 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -4,3 +4,4 @@ ragger[ledgerwallet]>=1.6.0 Jinja2==3.1.2 Flask==2.1.2 ecdsa>=0.16.1,<0.17.0 +Werkzeug==2.2.2 \ No newline at end of file From ccf767153f5923d2826166ad655bf0f341f1c79c Mon Sep 17 00:00:00 2001 From: Christopher Tarry Date: Wed, 22 Nov 2023 17:21:14 -0500 Subject: [PATCH 15/16] update snapshots --- .../00001.png | Bin 6861 -> 6914 bytes .../00001.png | Bin 6867 -> 6993 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/snapshots/stax/test_get_address_confirm_refused/00001.png b/tests/snapshots/stax/test_get_address_confirm_refused/00001.png index 1a2cabe4a844728530169f6d3bd7f2ecd7808c89..7f2cb3036afda4fd9a12c31151f969b33a76b48f 100644 GIT binary patch literal 6914 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 DEo8s* diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/00001.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/00001.png index 084e2bd7178396cf75d4711ae5ab7e0c8a12706d..18e6db50af16d410ec9f8dd49a2fdfa5722890aa 100644 GIT binary patch literal 6993 zcmeHMXh8B*K^K?xxYL=-Ve|7-uHD~_jBDZ53WOOmG&Om zyJgE3CA+JaowjV*`gqHhZ7+9k1D;qwDV1Bc{QQ&M<%`aUfqm{r6v|+JydDNlWA(R4@Iy66-x^cwpPsPDh$BxY5Irz~1^U zTa+f!+!FF8`L`Ul#mt31JEhXb=4WoF;1++YpPzk^b)uPr_CQHD8sd zK2)dfQA5Q;UD&ntHY(}ufz@^{(%68E4A^Yrg5-%R+*k7>DnSaum8^r zZC@z4U*h*TCgaO78$w=oP;9QvrS1^>Pdr|5_FoPA0#_cB6f#Wo8=GftozFlkWL(h} z_C|krEtv{Y(^tq)97CSZS#$NeTx(VZA_#3_UxA4)^zwGAX(K(W@-)3jW_Gn-YiwPg z{Sm%f&E;@#4U1#2_d4@PQ2p0SwPsTbZzx%T<`@1ruv~BgwwZ0P_G*H+aNTO>EJ91B zlWvor6K9260{5fP3gwu$LsjpP zcgo!Jg&sVZ8XhRiP)l!bv^aU?!P_Fg*zLjorLJT5{9=FBw{y~sviXiz#^~GljvHSu z*1o-?iJAEos90l)#^yfhZnex5Ej+SIJd%(J?2*O^FkRg|VoLsSPyf*~g^Z%+1?Ez- z*;uY$ZwEH`QLo;{e!Y>g=|^YXiZXT@wS7rjy#OM26q_sGE8o@jh$dIKN+uVP9-!JyPsqcxu7Y-cWqeeh^lKLJleXlOX z-L)ZZf7_qEHoWlGzVkd3ujT}-A(YX9?Fu{ORTZKQE9hkrHHX6v+Ei;;IwV>4J8fbQ#5UWDBN zfICv`Y-l#_YU~f`?U7eiC*Ij79og5m?frlB{{JlBdZ@Nr3}P%bcinA^F^eGgNF=Gv zqXeJuaS;S?H;Mx`q4yo~Ocz{x~(2Y+BhrC*0+! zrxxt{KEh;_FY;Y2#VKDXgs^Y3XIJl+tSSkvX=ZnLFZn_s`CT)Ww)_~gXYy703!B90<=Vto~;#0;iciWEWD;8|#m1PV^ z99&bt?h=ERev;f2LTeN;#F;QZ$At(+*f zv#Dk_v^u~%6|(?xv*ASC@Zh|h8TOazW)=Se;tZINddbiE5g;Or~L+dlS@D>j6?z8cEA1G-2>W_DS zd$KH*TD9s2I?U6HG$t1l^R;xOce|tJ9Pxj`)%ep)2Y(l|()3D!!%4BbMHUZE{xn+8 zCe+P_m&lGn(>l`@1c%Zd|LVENb17H5y*K2U{JDH0r?V7Q!8oh~O@TKb&hBX8RLh?0 zd+t%eSc_j-kON7tPP1nlXkDkkZp=igf#@{%Yy>%toKhBgZNSEGn)EFgFi}#pFYSi7 zkl5O^cnu2FPzExNq(&Z^>{rhQx}hq%vB8}n69Iw2U`X>R_CS%uvb6*Bj;WQ&$>Pu_iBumj2;^!q&QpWNQ3^Py}2tJWQdHj$-AY_aW=>l2gR(%3Uwz5(uTQAQZq%?QI(2WykF$r+m=aX@;(DVWbA-^lAX*AL#AI{KH z#$Y=lHty>MAB1%0VUwPB1+{RNV$2pq5cji=$#@HIAo2EN{OJS%m9v=G!Z83N@`R2IcXF;d4qonW^n&PGDMhyqM=M9?h9Z-KHjlL)g>ipzhWMNA8Tg#W8_I#ds4(g++I)w_KgyB7a(iH{*5uDO558DG zLA!?Al>@(2H8Dc79FqM0?B*205=0&vGCIq9@MackqU2dl7@rUf!0khQW4eXiYo0=c z>s~~nr6&lEmrFjl?j%mXHS&|tWxswuw6(M#nQT{^r^XlBzA?&ik-x(>hNUzKO9~5K zowjW>QhL^s(${)a=(slX=9Cr*bZ!V#wT?c@1=odAhujo&JIZFQpV|^>9$}3hg&O@{ zcT%t^yXF@VCa5RRq8B=oD@fU!C6_%g*nz%)(A4YXG1-Cqq5OgNnI79fdH;9(DXd$K z9_J&~K4t&i(Bdb1=~fhO^kTZ~J!2%3;uK`2;nPs*EZ$#396s$9(Qmt!r~b6i%W&O> zwd=HWY*nr7#9siF-39iFRf{Df@ShgCI!K$6&b8Q*-mlXq(=9v4!XjFoOF4%|27fEZ zZZl0|l{+#659YfbZKYDVe|+Kz%lpTyAVB_)dFJ3i+T;9vTff@}8v%HMa5o=Lc?pJ31H$1y& z)jHd%mr0L*Ga5-YujihvK_2Z)+F7YFsoB%Qi5i?w7>}EqkJso~K@=<{!;$EYCl8*a zyWnTo5y|8UPSPP|Oz6{jc*XM6)YN3m+fGcmAikvcl$H|-XuY6Zv7V{bOf7>R4`h~d z51w2*1yNmWrbL6;D+s+Lr_*KU7LmNDg9)({L!@In<|Wy6Ve$^1XTH(1#N*wPEI`Ob zs6F1fVe^wk5JKo)cLUsMShB35ex|HNaF*?KOCs>IX;l|=rKI&>8xLh(Ar0$Q9ks8i zKzmg4W7oHf6)*1{=t_8z1I1wb#l}Z%@M7~(TuY9t2m0~ zP^xQ%rGvKqff>K^`u;xhOEmXDGR?nL&}INMTM%9(v;SJHm&!!U^u(1~M;iPXsykUG zXstT!;5{?ynW)zd#uwcDs6B~HPVP)Xpiou(FfZkC8UdcO$pM{GZu{97-~2Koe${uw z{IKft=&-#5YlhSLSeHn#Ex-!wD3p<0nbX)TR&~d%=r#Q^jv82--_&n=4FyL>M|*={ z+R%pFoltQ6@IGGyt$q~;yYMd~_^1{R$kNgh3^t9t!`KhhM+|bS4rScMWe?Z$KRWt+ zG-c{v#r!bHe++q(B*-uCbfYxDEurJZNP2Yr{gvR2t~MP)B_IgFcG3F!fU%8>Ms^3| zmg_8xyg9i9|Fdy22DWrg`t2KxY)wvbl2%j${kDPiOP5t4@}U4(jMD@UO;1-_EoLW6 z6~#fx_r60`RHW0Tldbm2kg|D<*i+i1;b&$hIx%uA?Gq~%MqUGM^RYYS68Zpxg7F}|p#{kLA}?HY!ap@jy)4iz-F z@Zf`l`dAR56zuz1NfZw@e=ihUR@oZLVaiTqInWfUT!9B#HMr<1%RzLjA;z(Cj@k4l zGyGH1)$qS{DwTDu3sL@_>rD9_baL&wMB2&yo~Y*8QB`6tYX6AJ#09Z9#KOqLyoK&8 zY1GvDdBy-ZddffXkzcktyu+{X@MOvkk2iM!n+1<*mU*r9`*5I!Y+AZ}y6$|d9;`L_ zNz9p_9$hKnM7a(BhV8yI8rwb{V>ZSYVaazVW6bb9sS80j(0}8BQZbchKPhP2MwsLu zR>rJ5Mssgj;54(?g6G_t!?^EyoG{FcK@pu$bID;FyUP^K8o`4|P))(rN(sbs_OhaO z$2m^lO6->ncKq#8ehzecD0&(B(u*u!$SA#Q$=Y~UZv76zAbib(5V)dE>MHuE=&6hu z>YHnD+-qFU+UrYFe_u8w4&StC+gJnamrTsVuL?W)xBghd8LG-$1c^Op%+$LcksE(j zc7Xy|MhrdvNYnB09l%%Hnel>B%x2z>T+{-G~sQ(%}=M@ls?-;s$|>~J%f-% z8yh3>ZFP%@l5gJ-IOcA;O2CulsP8_L`MZ*gsyP>9<}jGeFfF?_BfWQ1la6{pZ_XDy zd<~dC;QACv`opjWf5ez+sAbsr>~shGDywRFP?adD@G6cY4fnZe_5=aV4wrud=J#Y- zIjh5;_887JN<2`~8&U@=y>^OFoM$lZ5*47aZ|Bqs!lJOq3x{8Nv6KUG%#l5nn-xM@ zyz~K^FvH#juqn&BYH%J&#^pYtJQ#=Kd^}Rl0mdf6gygtPsKqWzu(;bx_506YK2Kwf zbk)haF4b-Y)572~M{jK?p`W%^bviG!ZJkwI&Ytb8wDTonmsx~sfRE@jJx6tWqdH#b z$GI4Fxg&gWNhIlN)iEukdW1>sKL*x%Kx9evJ23QOl*w!O{sXeI_hq^If26+8$WuEd!Q=-Fl4DH&1t2TjP#Jst4ep-i6?h>?E$zs?V@HFCF z@`JR6kDw=r()51GtRRBlxq*Y~z>)%*?x!}RN7*rEmMvV}Xba+1TfG5!5kU-p2lT(q zaP~t|!@ai?eBl@a7)3fJu)?S^BoEm$o&xqJ=PwO!B_D4&KX#M7-<(>u$8hl!UQ`gm zYS=(pYVtC!;<5|UqC8x{8p^t}dYG`eAn{2g66qCpCXP?gl@B$%r=e^>6V|mfPxFf= zj?U_K>aThvN(o85o8IEjoLzdD6a>O7Rj#WzE}3Pp8Y#__F$f|5Cxc`E0OMw$02o^! za#Wsnr@^I{223S08h!X`YI}M@QhLI!oX%hL<6I1kCjx+>BN+qqy=t&d`1wPbfK)y7 zv1&fRn5G03#z;d6IzNvM^2`q(U2TQyhT@1x9t!x z_K1pny_w1$cJVpzOe&BT~*xS7t@aZ`mOU-QHXn=he$=)^G09fbfs3*;u97ru_ zvT&~)g?MvUeSJ^hBbr8={s|-o&fuF}NX`UMRUTTM>yG;C^Uu2nP}7mTj;T7hE0G0w zaTLlCOxXUY1>D}HT{}jMM^|qgF2dt||A{y~mXG=@Z}XDQo6$u&oh}p#*N%@#W?99( zv%GRQZ5TNHur0r=Ao!p%MkuC?WyZBmxCxwxqg%#E$fi*jO-lXqWI=L%mPXXbRD+kU z@e2o?)Jnh+XN8gDlBEZkoDkin8JsV8fWR#W-jde5(RLpz{~g%WrgrHSt*DHqdlN1= zQY26&4M%*xk1EB;A{A9iWGyKCa6wnl_xozWP>x8fX#cGarZ=MEt(WxK!BbUm*duCA z8jo+(0mdc3xKlQLiomwDOTexR3x`CLF+=ft^KzALVc8K_YwsV3q~l}peci)2_q0sz zMVwvtWu_w)ZxA}-V16i*an5D;02PKw2nI$9eQAF%k(KX?_DrYtj^G_@Rs%F4>rG6lTgwKCB(@d_x+*u^F+bxh4G zV~v{N-MpfbnfH<$BQyj=MHC`L0|W&Bud~)!>wGz1&RS=!^I`Tk-u>>q-`{0F&-457 z`(-z0tu6Xn)~#Eob>aLOk9F(TXRKSd;m^$*fG76u?WA?<^z$#AIpvvHC}c9?K21Km zcZHY6Tz4d6*KN%f4UY{LCKg>5>o5Mi|0M9!FXd1d?^HHN}F5@+IrX|iqLFQD?&6FO!?yEGL%7~*WfnpHv zFQUq!zK1+EH~fnq5n?R6yTUXNI@+I6AA7_?q8)w(&(Xj)OTG_1e{--e){&NO3_gap z^WHzB1^*qDoNSo+w78_wXz@VTGk5o@VU*9iV1uq_qXS84zP0*lhy1hJT~me@op}TC zhgoN9k5_g4wR9>v3|w{3ylu0NX_8M>Td`lm@e8$jQD-1e9>i?caowm}Lrm>BeA4j_ ztUq{j*OXS&m!Und9J@_*>x=C)b#Qtf1ZfD%0P$w;M&oYq+1j}nWCgFI&s{5^xIW`7 zxGOk~^R8an_l>5`KCQ4EpJ?xtp4Ik*f-ATN3y;GEbq6(diddNWr=I{r&d~=KbsaVE zFc144_rZ%wBGJT?Vru1C@`qPD~mhb-ord%;=qjQi3Fng{rf8)N*Iz0X8MeDSE zuvqgqy5dM7?1%6VYvP%ZuHjU`@R2hx!*bE2v4h2L9;qK#u3p{J^9BdBy6)-@n&2 zf%)D4Nvs(WyXpTCfKRWPx1xI7H%+6_u362a-j0r5mDG+$KtRa;TK1{I*fM2CpkaC+ zkH@RVm}U*c+N<7Y4&P`<&{D3f_)$2Z;7_38wKeJUvGxn2R>2uD6HKO~gM%L&u2QR% zYIUdTR|z^9gYjk6Gb4FR@{AzL?@#6<#)R?i?(Vem8}>zR<)iW>HM2muyu6GKBhmQp z#1^?j-JFF}`;tYq_?~C_x9ebjxBmd0QvDIyFrLwuYg{gjSB_-K78gC#BLV*Y`r0sy zT%oM@)jxZiGuiBfdto2~?)9FKmzIqCjs7(_^-8OM4F$15yn?J{s3knK) ztwb_0hf%9fcsMPF)%*ci?6t(5p_@CI=ME{XalleagzxZ*djSvNavHC_qxvO7$j2FP zPn8ZPQfmoe%?vMVlzmZg;U7^}MNw!hwzIR-;;K!N8|l$~;5=>u3*7-S0v4wS94lpl z(Af*`HpM#5PVEzBk}obR6h2Y4n3$^CmE%I0lA70UM8T~Z9p?s+iihW86|_-g&f?)9 z5TUtwpb|ntYKqlrwM$t;AH8xH;NE&m$TsQ~x^#ZN!Vi6mMBfB>79(@X_#%}yu?{!F z%$pduFq!eKeqUtDHg8(--6-zR_He+>+S=MQgNX=RiT=e#-V~pYuq`N>=wF=Oi0GS+ z?(nB;W0%A#>QxoSzUbp`Hyv&?jC*dSWer@jEjXfs&nmDUEa&GJ1HMMb&A*Fl<|4hL ze7$Sv@bG(F#pFQl0!tSe7uN{*DftpD9GD<8za%IhSIb! z%vjcU?ZAuWMD@w2FZ?438D9GwnP| zOu@|!d=vabj|`QF&f9q{6dQ?k_v%~L#NYK0#_|NJ3GlVW6%Bc zzG;ahj&3Hr(a_r38us~d1v`n`d=>MGZ|sOaU23xC-9Tmd?KfM)mL&o@`NrqG$9*AG z|5*eSijhKoQMTPsqC0@}Q$LtDPZ+i>TjEg(+~L$FAkVY3$0BTL$oD(AyXG<^X+j*0 zAwm$q+N%rqTwtcTTP^DEdL{2A?Utyp6lUa*yZV|{m_sPt?pkaAZRAL0(#b~k>f$2u zxWQnQTI%7>#AofX8Pc^{x!j1f`XtNQy4BR#{>!}&xJv$R*8^ES!F4`W5R#Y528(0? zxu?PgfKiPzzK3+V=p4U6cV-d@mz3mSu$>`nDxB=KT|_$Gv@eQmW+42Os?H=i*Yug< zeGX}Z#1!==782Fp&8cOJ_L$r>fA!JHDfuK&NtX zpXcx!yoP{J-7me^>N&CezBs8nTa=dNGQ!nkXdi?o>3=s$>6Ni0T^Hr2Zm}5@&~e4R zCxqVdhN&``Q7nZoVhGRU}|R{!`&wsP(9{Abiqhx$awo{hH13BB6Y zFvcL&M;Rlwc+TULCVAHmf-kf#ATtBws#x>}a$N=u+nwFW&p#_^h)WL7cG)w& zrFJtdGKjoTc&|$>8=uqlQ12u+;giqQDw=DbeD{%ME?HhqM0yCeyd)j7hef%C(seJK z2ywS?>X5%J1>khH0M!z`wBP|s+5>4UErSTP&FBnpur7w)G={!!`#9hhkQ>mB5sp|~ z7v3DG+6GVE`Z4NjZ_A){lfJJV|B+SJzzn=EJ|{}tn^T1BhG0CXD3iu4Mi1z`Nm{VG*5{f21qIYYubNVnXJHBWH?>dDew5t=Su>idwng~fw@xru% zcQ@dB7L{5jZ~{0e)~G3&%e_v#RjP}tkvRmR=mXlk8x4opn;h|2?xa&Z{ut{Zz&=|b zjT$~iBUe=+Zz`<0VfJKZ^@QR0QekLk#$f2Tq{7La(@bG}!MidLl0Utza2Oy@$Hkei ze%E?)Xyks9`Xy>i%IQMjW=UrU7hA~GV|kZ|=@S_>`M}-E&CSKPhv`2j4ReSd^#GWK zm{2rt{`(>2n61(w844Db({z!@dctMzQY1Te5hp z2vJqL9YVLCm0Qka*?bgil9E8 z%)*i%(rD1P-Az#me_>Rif-R#N*N2NY;srQ@pT`T!*K(yyq*$MjkRTM5A{TyR`v6(y z?m#MfkM7Pu?JbkAW&dm&A zbxloFR1{fS{9z|RRFaV4iN8Iy{XwDBx_!DR6GCO=sW|&+<$79=)D1ftD}Rs+apMha zdSbouqpu$3N#ECF)epTs0YvH`jlIT_%>5`O& z)1EaC?a83Sz<+*HjE=>Q>GAKRNYMP(+VH;0B8QRSuMX``M0%CooZHClZU?d!)5ePf zB?kESI0b7!=Dg}%6ctJNOv!f+>6^$aM;9dx|F+XWe7f^z0Q_!~H#jO!?#X?CNGEj+ z+*sybSJ=4`9GYjRQzZ72+Dur(p(1N-%PGdK?zXnJe7ACdJ;Yu=6R3Ma@5-KDIw0gS z5I-co3DV&j&(muH9(AmzWox>*jUii;P^fvf1X5hK#2Sr87dNbkUcK7^fB_ZidK*I| zy1OZ#(bTo_x{v{`J6oBhunIfDx$ly(xoH+uVRYi#L~i# z*w~`OGS?5fNCUgXI#CphP3ess6g^1U4Y%4D>&l<(W#l-%J_Sf(|!NBn{CAw*X#qzHuCTWrGMi0ilk|(iRWI%b< z*<3euRb3g2DSFY~oCF1=zCtRDXXp`E#E zV9~^kXVjapnM#3FYHbM=EWLc0mA+jL{~H28U@VXY?71^Eih!748C3*w>o4j>0ENoL zD?i-qkk@PA+Z7Zzqk*(W_m?fJ4AT41!b-pR!!+$`;}f5Nh+uYY+J4?5)kZ^Lza_}F zfCfGYKMZEUDdX08m-NZ2LnUsJZ#&!C%E2%lYT7UJC z;Vo16?Z)tlIR!pUY*rMgIy`s}&+*M4Oig}W9}y$>Z%J+qY!T+*#{7~&OVz5 zlwS7kb2EvU$5aH{1|2KmK>McalIw#|Zo9e+=8ekzFZ0_zoKlSd74jpperg&}wgE5= zluVHh2;*Ru5u$NTD%XcYtGd4oZ9HB+IuBeK`^h^4HmlnK*`BtXEkMTU1J zy369_stnrni7AX8}gW%4ovwE{(9G) From 7764d442ccb875cad2d7cf869e458e1de67c7f77 Mon Sep 17 00:00:00 2001 From: Christopher Tarry Date: Mon, 27 Nov 2023 12:19:12 -0500 Subject: [PATCH 16/16] remove accidentally added formatSC call for Siafund values on Stax --- src/calcTxnHash_nbgl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/calcTxnHash_nbgl.c b/src/calcTxnHash_nbgl.c index aa66705..b2e4fcb 100644 --- a/src/calcTxnHash_nbgl.c +++ b/src/calcTxnHash_nbgl.c @@ -58,8 +58,7 @@ static void fmtTxnElem(void) { memmove(ctx->labelStr, "SF Output #", 11); bin2dec(ctx->labelStr + 11, display_index()); format_address(ctx->fullStr[0], txn->elements[ctx->elementIndex].outAddr); - const uint8_t valLen = cur2dec(ctx->fullStr[1], txn->elements[ctx->elementIndex].outVal); - formatSC(ctx->fullStr[1], valLen); + cur2dec(ctx->fullStr[1], txn->elements[ctx->elementIndex].outVal); break; }